feat!: Reworked debugger loading logic

This commit is contained in:
FalsePattern 2024-05-31 23:11:56 +02:00
parent dc830beed2
commit 7c32d93ea0
Signed by: falsepattern
GPG key ID: E930CDEC50C50E23
61 changed files with 1436 additions and 584 deletions

View file

@ -17,6 +17,12 @@ Changelog structure reference:
## [Unreleased] ## [Unreleased]
- Debugging
- Major update, debugging on linux now works outside CLion (confirmed working in RustRover, IDEA Ultimate)
- Windows debugging has been made much more streamlined, user doesn't need to download random files manually anymore
(except the visual studio debugging sdk of course)
- debugging support on macOS with LLDB
## [14.5.0] ## [14.5.0]
### Changed ### Changed

View file

@ -34,7 +34,11 @@ These art assets are licensed under Creative Commons Attribution-ShareAlike 4.0
Parts of the codebase are based on the intellij-zig plugin, Parts of the codebase are based on the intellij-zig plugin,
developed by HTGAzureX1212 (https://github.com/HTGAzureX1212), licensed under the Apache 2.0 license. developed by HTGAzureX1212 (https://github.com/HTGAzureX1212), licensed under the Apache 2.0 license.
-------------------------------- --------------------------------
Parts of the codebase are based on the intellij-rust plugin,
developed by the intellij-rust team (https://github.com/intellij-rust), licensed under the intellij-rust MIT license.
--------------------------------
All of the licenses listed here are available in the following files, bundled with the plugin: All of the licenses listed here are available in the following files, bundled with the plugin:
- licenses/APACHE_2.0.LICENSE - licenses/APACHE_2.0.LICENSE
- licenses/CC_BY_SA_4.0.LICENSE - licenses/CC_BY_SA_4.0.LICENSE
- licenses/INTELLIJ-RUST.LICENSE

View file

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Aleksey Kladov, Evgeny Kurbatsky, Alexey Kudinkin and contributors
Copyright (c) 2016 JetBrains
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,19 @@
package com.falsepattern.zigbrains;
import com.intellij.DynamicBundle;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.PropertyKey;
public class ZigBundle extends DynamicBundle {
public static final String BUNDLE = "zigbrains.Bundle";
public static final ZigBundle INSTANCE = new ZigBundle();
private ZigBundle() {
super(BUNDLE);
}
@Nls
public static String message(@PropertyKey(resourceBundle = BUNDLE) String key, Object... params) {
return INSTANCE.getMessage(key, params);
}
}

View file

@ -0,0 +1,9 @@
package com.falsepattern.zigbrains.common;
import org.jetbrains.annotations.NotNull;
/**
* Evil hack for bypassing plugin verifier restrictions via generics. Unfortunately this is necessary due to public api limitations.
*/
public record ObjectHolder<T>(@NotNull T value) {
}

View file

@ -0,0 +1,16 @@
package com.falsepattern.zigbrains.common;
import com.intellij.openapi.application.PathManager;
import java.nio.file.Path;
import java.nio.file.Paths;
public class ZigPathManager {
public static Path pluginDirInSystem() {
return PathManager.getSystemDir().resolve("zigbrains");
}
public static Path tempPluginDirInSystem() {
return Paths.get(PathManager.getTempPath()).resolve("zigbrains");
}
}

View file

@ -0,0 +1,24 @@
inlayprovider=ZLS Inlay Provider
notif-zb=ZigBrains general notification
notif-zig-project=Zig project notification
notif-zls-error=ZLS error notification
notif-debug-info=ZigBrains debugger info
notif-debug-warn=ZigBrains debugger warning
notif-debug-error=ZigBrains debugger error
dialog.title.download.debugger=Download Debugger
notification.nativedebug.title=Zig native debugger
notification.nativedebug.text=You need to install the "Native Debugging Support" plugin for Zig debugging in this IDE!
notification.nativedebug.market=Install from Marketplace
notification.nativedebug.browser=Open in Browser
notification.title.debugger=Debugger
notification.content.debugger.successfully.downloaded=Debugger successfully downloaded
notification.content.debugger.downloading.failed=Debugger downloading failed
notification.content.debugger.metadata.downloading.failed=Debugger metadata downloading failed
settings.debugger.toolchain.download.debugger.automatically.checkbox=Download and update the debugger automatically
settings.debugger.title=Zig
settings.debugger.toolchain.debugger.label=Debugger:
settings.debugger.toolchain.download.comment=Need to be <a>downloaded</a>
settings.debugger.toolchain.update.comment=Need to be <a>updated</a>
settings.debugger.toolchain.use.clion.toolchains=Use Clion toolchains instead
notification.content.debugger.need.download=You need to download/update the debugger before you can run debugging! (Settings | Build, Execution, Deployment | Debugging -> Zig)
unable.to.run.debugger=Unable to Run Debugger

View file

@ -14,11 +14,14 @@
* limitations under the License. * limitations under the License.
*/ */
package com.falsepattern.zigbrains.cpp; package com.falsepattern.zigbrains.clion;
import com.falsepattern.zigbrains.debugbridge.DebuggerDriverProvider; import com.falsepattern.zigbrains.common.ObjectHolder;
import com.falsepattern.zigbrains.debugbridge.ZigDebuggerDriverConfigurationProvider;
import com.falsepattern.zigbrains.debugger.settings.ZigDebuggerSettings;
import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.SystemInfo;
import com.jetbrains.cidr.cpp.execution.debugger.backend.CLionGDBDriverConfiguration; import com.jetbrains.cidr.cpp.execution.debugger.backend.CLionGDBDriverConfiguration;
import com.jetbrains.cidr.cpp.execution.debugger.backend.CLionLLDBDriverConfiguration; import com.jetbrains.cidr.cpp.execution.debugger.backend.CLionLLDBDriverConfiguration;
import com.jetbrains.cidr.cpp.toolchains.CPPToolchains; import com.jetbrains.cidr.cpp.toolchains.CPPToolchains;
@ -26,10 +29,17 @@ import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
import lombok.val; import lombok.val;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public class CPPDebuggerDriverProvider implements DebuggerDriverProvider { public class ZigClionDebuggerDriverConfigurationProvider implements ZigDebuggerDriverConfigurationProvider {
private static final Logger LOG = Logger.getInstance(CPPDebuggerDriverProvider.class); private static final Logger LOG = Logger.getInstance(ZigClionDebuggerDriverConfigurationProvider.class);
@Override @Override
public @Nullable DebuggerDriverConfiguration getDebuggerConfiguration(Project project) { public @Nullable ObjectHolder<DebuggerDriverConfiguration> getDebuggerConfiguration(Project project, boolean isElevated, boolean emulateTerminal) {
if (SystemInfo.isWindows)
return null;
if (!ZigDebuggerSettings.getInstance().useClion)
return null;
val toolchains = CPPToolchains.getInstance(); val toolchains = CPPToolchains.getInstance();
var toolchain = toolchains.getToolchainByNameOrDefault("Zig"); var toolchain = toolchains.getToolchainByNameOrDefault("Zig");
if (toolchain == null || !toolchain.isDebuggerSupported()) { if (toolchain == null || !toolchain.isDebuggerSupported()) {
@ -42,8 +52,8 @@ public class CPPDebuggerDriverProvider implements DebuggerDriverProvider {
} }
return switch (toolchain.getDebuggerKind()) { return switch (toolchain.getDebuggerKind()) {
case CUSTOM_GDB, BUNDLED_GDB -> new CLionGDBDriverConfiguration(project, toolchain); case CUSTOM_GDB, BUNDLED_GDB -> new ObjectHolder<>(new CLionGDBDriverConfiguration(project, toolchain));
case BUNDLED_LLDB -> new CLionLLDBDriverConfiguration(project, toolchain); case BUNDLED_LLDB -> new ObjectHolder<>(new CLionLLDBDriverConfiguration(project, toolchain));
}; };
} }
} }

View file

@ -1,43 +0,0 @@
/*
* 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.debugbridge;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.UserDataHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.stream.Stream;
/**
* getDebuggerConfiguration should return com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration, it's UserDataHolder here to
* avoid a plugin verifier error.
*/
public interface DebuggerDriverProvider {
ExtensionPointName<DebuggerDriverProvider> EXTENSION_POINT_NAME = ExtensionPointName.create("com.falsepattern.zigbrains.debuggerDriverProvider");
static @NotNull Stream<UserDataHolder> findDebuggerConfigurations(Project project) {
return EXTENSION_POINT_NAME.getExtensionList()
.stream()
.map(it -> it.getDebuggerConfiguration(project))
.filter(Objects::nonNull);
}
@Nullable UserDataHolder getDebuggerConfiguration(Project project);
}

View file

@ -0,0 +1,42 @@
/*
* 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.debugbridge;
import com.falsepattern.zigbrains.common.ObjectHolder;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.project.Project;
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Stream;
public interface ZigDebuggerDriverConfigurationProvider {
ExtensionPointName<ZigDebuggerDriverConfigurationProvider> EXTENSION_POINT_NAME = ExtensionPointName.create("com.falsepattern.zigbrains.debuggerDriverProvider");
static @NotNull Stream<Supplier<DebuggerDriverConfiguration>> findDebuggerConfigurations(Project project, boolean isElevated, boolean emulateTerminal) {
return EXTENSION_POINT_NAME.getExtensionList()
.stream()
.map(it -> (Supplier<DebuggerDriverConfiguration>) () -> Optional.ofNullable(it.getDebuggerConfiguration(project, isElevated, emulateTerminal))
.map(ObjectHolder::value)
.orElse(null));
}
@Nullable ObjectHolder<DebuggerDriverConfiguration> getDebuggerConfiguration(Project project, boolean isElevated, boolean emulateTerminal);
}

View file

@ -16,45 +16,13 @@
package com.falsepattern.zigbrains.debugger; package com.falsepattern.zigbrains.debugger;
import com.falsepattern.zigbrains.debugbridge.DebuggerDriverProvider;
import com.falsepattern.zigbrains.debugger.win.WinDebuggerDriverConfiguration;
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.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.project.Project;
import com.intellij.util.system.OS;
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
import com.jetbrains.cidr.execution.debugger.backend.lldb.LLDBDriverConfiguration;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.val; import lombok.val;
import org.jetbrains.annotations.Nullable;
public class Utils { public class Utils {
public static @Nullable DebuggerDriverConfiguration getDebuggerConfiguration(Project project) {
if (OS.CURRENT == OS.Windows) {
return new WinDebuggerDriverConfiguration();
}
val providedDebugger = DebuggerDriverProvider.findDebuggerConfigurations(project)
.filter(x -> x instanceof DebuggerDriverConfiguration)
.map(x -> (DebuggerDriverConfiguration)x)
.findFirst()
.orElse(null);
if (providedDebugger != null)
return providedDebugger;
if (LLDBDriverConfiguration.hasBundledLLDB()) {
Notifications.Bus.notify(new Notification("ZigBrains.Debugger.Warn",
"Couldn't find a working debug toolchain, using bundled LLDB debugger!",
NotificationType.WARNING));
return new LLDBDriverConfiguration();
} else {
return null;
}
}
public static void executeCommandLineWithErrorChecks(GeneralCommandLine cli) throws ExecutionException, ProcessException { public static void executeCommandLineWithErrorChecks(GeneralCommandLine cli) throws ExecutionException, ProcessException {
val outputOpt = CLIUtil.execute(cli, Integer.MAX_VALUE); val outputOpt = CLIUtil.execute(cli, Integer.MAX_VALUE);

View file

@ -0,0 +1,225 @@
package com.falsepattern.zigbrains.debugger;
import com.falsepattern.zigbrains.ZigBundle;
import com.falsepattern.zigbrains.common.ObjectHolder;
import com.falsepattern.zigbrains.debugbridge.ZigDebuggerDriverConfigurationProvider;
import com.falsepattern.zigbrains.debugger.settings.ZigDebuggerSettings;
import com.falsepattern.zigbrains.debugger.toolchain.DebuggerAvailability;
import com.falsepattern.zigbrains.debugger.toolchain.DebuggerAvailability.GDBBinaries;
import com.falsepattern.zigbrains.debugger.toolchain.DebuggerAvailability.LLDBBinaries;
import com.falsepattern.zigbrains.debugger.toolchain.DebuggerAvailability.MSVCBinaries;
import com.falsepattern.zigbrains.debugger.toolchain.DebuggerKind;
import com.falsepattern.zigbrains.debugger.toolchain.ZigDebuggerToolchainService;
import com.falsepattern.zigbrains.debugger.win.MSVCDriverConfiguration;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DoNotAskOption;
import com.intellij.openapi.ui.MessageDialogBuilder;
import com.intellij.openapi.ui.Messages;
import com.jetbrains.cidr.ArchitectureType;
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
import com.jetbrains.cidr.execution.debugger.backend.gdb.GDBDriverConfiguration;
import com.jetbrains.cidr.execution.debugger.backend.lldb.LLDBDriverConfiguration;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.nio.file.Path;
public class ZigDefaultDebuggerDriverConfigurationProvider implements ZigDebuggerDriverConfigurationProvider {
private static boolean availabilityCheck(Project project, DebuggerKind kind) {
val service = ZigDebuggerToolchainService.getInstance();
val availability = service.debuggerAvailability(kind);
final String message, action;
switch (availability.kind()) {
case Bundled, Binaries -> {
return true;
}
case Unavailable -> {
return false;
}
case NeedToDownload -> {
message = "Debugger is not loaded yet";
action = "Download";
}
case NeedToUpdate -> {
message = " Debugger is outdated";
action = "Update";
}
default -> throw new AssertionError("This should never happen");
}
val downloadDebugger = ZigDebuggerSettings.getInstance().downloadAutomatically || showDialog(project, message, action);
if (downloadDebugger) {
val result = ZigDebuggerToolchainService.getInstance().downloadDebugger(project, kind);
if (result instanceof ZigDebuggerToolchainService.DownloadResult.Ok)
return true;
}
return false;
}
private static boolean showDialog(Project project, String message, String action) {
val doNotAsk = new DoNotAskOption.Adapter() {
@Override
public void rememberChoice(boolean isSelected, int exitCode) {
if (exitCode == Messages.OK) {
ZigDebuggerSettings.getInstance().downloadAutomatically = isSelected;
}
}
};
return MessageDialogBuilder.okCancel(ZigBundle.message("unable.to.run.debugger"), message)
.yesText(action)
.icon(Messages.getErrorIcon())
.doNotAsk(doNotAsk)
.ask(project);
}
@Override
public @Nullable ObjectHolder<DebuggerDriverConfiguration> getDebuggerConfiguration(Project project, boolean isElevated, boolean emulateTerminal) {
val settings = ZigDebuggerSettings.getInstance();
val service = ZigDebuggerToolchainService.getInstance();
val kind = settings.debuggerKind;
if (!availabilityCheck(project, kind)) {
return null;
}
val availability = service.debuggerAvailability(kind);
return switch (availability.kind()) {
case Bundled -> new ObjectHolder<>(switch (kind) {
case LLDB -> new ZigLLDBDriverConfiguration(isElevated, emulateTerminal);
case GDB -> new ZigGDBDriverConfiguration(isElevated, emulateTerminal);
case MSVC -> throw new AssertionError("MSVC is never bundled");
});
case Binaries -> {
val bin = (DebuggerAvailability.Binaries) availability;
yield new ObjectHolder<>(switch (bin.binariesKind()) {
case LLDB -> new ZigCustomBinariesLLDBDriverConfiguration((LLDBBinaries) bin, isElevated, emulateTerminal);
case GDB -> new ZigCustomBinariesGDBDriverConfiguration((GDBBinaries) bin, isElevated, emulateTerminal);
case MSVC -> new ZigMSVCDriverConfiguration((MSVCBinaries) bin, isElevated, emulateTerminal);
});
}
case Unavailable, NeedToDownload, NeedToUpdate -> throw new AssertionError("This should never happen");
};
}
//region GDB
@RequiredArgsConstructor
public static class ZigGDBDriverConfiguration extends GDBDriverConfiguration {
private final boolean isElevated;
private final boolean emulateTerminal;
@Override
public @NotNull String getDriverName() {
return "Zig GDB";
}
// TODO: investigate attach to process feature separately
@Override
public boolean isAttachSupported() {
return false;
}
@Override
public boolean isElevated() {
return isElevated;
}
@Override
public boolean emulateTerminal() {
return emulateTerminal;
}
}
private static class ZigCustomBinariesGDBDriverConfiguration extends ZigGDBDriverConfiguration {
private final GDBBinaries binaries;
public ZigCustomBinariesGDBDriverConfiguration(GDBBinaries binaries, boolean isElevated, boolean emulateTerminal) {
super(isElevated, emulateTerminal);
this.binaries = binaries;
}
@Override
protected @NotNull String getGDBExecutablePath() {
return binaries.gdbFile().toString();
}
}
//endregion GDB
//region LLDB
@RequiredArgsConstructor
public static class ZigLLDBDriverConfiguration extends LLDBDriverConfiguration {
private final boolean isElevated;
private final boolean emulateTerminal;
@Override
public @NotNull String getDriverName() {
return "Zig LLDB";
}
@Override
public boolean isElevated() {
return isElevated;
}
@Override
public boolean emulateTerminal() {
return emulateTerminal;
}
}
private static class ZigCustomBinariesLLDBDriverConfiguration extends ZigLLDBDriverConfiguration {
private final LLDBBinaries binaries;
public ZigCustomBinariesLLDBDriverConfiguration(LLDBBinaries binaries, boolean isElevated, boolean emulateTerminal) {
super(isElevated, emulateTerminal);
this.binaries = binaries;
}
@Override
public boolean useSTLRenderers() {
return false;
}
@Override
protected @NotNull File getLLDBFrameworkFile(@NotNull ArchitectureType architectureType) {
return binaries.frameworkFile().toFile();
}
@Override
protected @NotNull File getLLDBFrontendFile(@NotNull ArchitectureType architectureType) {
return binaries.frontendFile().toFile();
}
}
//endregion LLDB
//region MSVC
@RequiredArgsConstructor
public static class ZigMSVCDriverConfiguration extends MSVCDriverConfiguration {
private final MSVCBinaries binaries;
private final boolean isElevated;
private final boolean emulateTerminal;
@Override
public @NotNull String getDriverName() {
return "Zig MSVC";
}
@Override
protected Path getDebuggerExecutable() {
return binaries.msvcFile();
}
@Override
public boolean isElevated() {
return isElevated;
}
@Override
public boolean emulateTerminal() {
return emulateTerminal;
}
}
//endregion MSVC
}

View file

@ -16,6 +16,7 @@
package com.falsepattern.zigbrains.debugger; package com.falsepattern.zigbrains.debugger;
import com.falsepattern.zigbrains.debugger.runner.base.PreLaunchAware;
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;
@ -41,19 +42,21 @@ public class ZigLocalDebugProcess extends CidrLocalDebugProcess {
PostStart, PostStart,
Unsuppressed Unsuppressed
} }
private volatile SuppressionLevel suppressionLevel = SuppressionLevel.PreStart; private volatile SuppressionLevel suppressionLevel;
private final List<Runnable> preStart = new ArrayList<>(); private final List<Runnable> preStart = new ArrayList<>();
private final List<Runnable> postStart = 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);
suppressionLevel = parameters instanceof PreLaunchAware ? SuppressionLevel.PreStart : SuppressionLevel.Unsuppressed;
} }
public void doStart() { public void doStart() {
start(); start();
lock.lock(); lock.lock();
try { try {
suppressionLevel = SuppressionLevel.PostStart; if (suppressionLevel == SuppressionLevel.PreStart)
suppressionLevel = SuppressionLevel.PostStart;
} finally { } finally {
lock.unlock(); lock.unlock();
} }
@ -82,7 +85,8 @@ public class ZigLocalDebugProcess extends CidrLocalDebugProcess {
lock.lock(); lock.lock();
try { try {
if (suppressionLevel == SuppressionLevel.Unsuppressed) val level = suppressionLevel;
if (level == SuppressionLevel.Unsuppressed)
return original.get(); return original.get();
val bypass = new CompletableFuture<T>(); val bypass = new CompletableFuture<T>();
@ -93,7 +97,7 @@ public class ZigLocalDebugProcess extends CidrLocalDebugProcess {
bypass.completeExceptionally(ex); bypass.completeExceptionally(ex);
return null; return null;
}); });
switch (suppressionLevel) { switch (level) {
case PreStart -> preStart.add(task); case PreStart -> preStart.add(task);
case PostStart -> postStart.add(task); case PostStart -> postStart.add(task);
} }

View file

@ -16,8 +16,6 @@
package com.falsepattern.zigbrains.debugger.runner.base; package com.falsepattern.zigbrains.debugger.runner.base;
import java.util.concurrent.CompletableFuture;
public interface PreLaunchAware { public interface PreLaunchAware {
void preLaunch() throws Exception; void preLaunch() throws Exception;
} }

View file

@ -16,10 +16,8 @@
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,12 +23,9 @@ 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

@ -20,7 +20,6 @@ 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.intellij.execution.ExecutionException; import com.intellij.execution.ExecutionException;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.io.FileUtil; 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;
@ -29,7 +28,6 @@ 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> implements PreLaunchAware { public abstract class ZigDebugParametersEmitBinaryBase<ProfileState extends ProfileStateBase<?>> extends ZigDebugParametersBase<ProfileState> implements PreLaunchAware {
protected volatile File executableFile; protected volatile File executableFile;

View file

@ -17,11 +17,12 @@
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.common.util.ApplicationUtil;
import com.falsepattern.zigbrains.debugbridge.ZigDebuggerDriverConfigurationProvider;
import com.falsepattern.zigbrains.debugger.Utils;
import com.falsepattern.zigbrains.debugger.ZigLocalDebugProcess;
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.ZigLocalDebugProcess;
import com.intellij.execution.ExecutionException; import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.executors.DefaultDebugExecutor; import com.intellij.execution.executors.DefaultDebugExecutor;
@ -32,9 +33,6 @@ import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.ConsoleView;
import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.execution.ui.RunContentDescriptor; 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.openapi.application.ApplicationManager;
import com.intellij.xdebugger.XDebugProcess; import com.intellij.xdebugger.XDebugProcess;
import com.intellij.xdebugger.XDebugProcessStarter; import com.intellij.xdebugger.XDebugProcessStarter;
@ -68,9 +66,18 @@ public abstract class ZigDebugRunnerBase<ProfileState extends ProfileStateBase<?
protected RunContentDescriptor doExecute(ProfileState state, AbstractZigToolchain toolchain, ExecutionEnvironment environment) protected RunContentDescriptor doExecute(ProfileState state, AbstractZigToolchain toolchain, ExecutionEnvironment environment)
throws ExecutionException { throws ExecutionException {
val project = environment.getProject(); val project = environment.getProject();
val debuggerDriver = Utils.getDebuggerConfiguration(project); val providers = ZigDebuggerDriverConfigurationProvider.findDebuggerConfigurations(project, false, false)
.toList();
DebuggerDriverConfiguration debuggerDriver = null;
for (val provider: providers) {
debuggerDriver = provider.get();
if (debuggerDriver != null)
break;
}
if (debuggerDriver == null) { if (debuggerDriver == null) {
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;
} }
ZigDebugParametersBase<ProfileState> runParameters = getDebugParameters(state, environment, debuggerDriver, toolchain); ZigDebugParametersBase<ProfileState> runParameters = getDebugParameters(state, environment, debuggerDriver, toolchain);
@ -132,10 +139,9 @@ public abstract class ZigDebugRunnerBase<ProfileState extends ProfileStateBase<?
} }
}; };
val process = new ZigLocalDebugProcess(params, session, wrappedBuilder); val process = new ZigLocalDebugProcess(params, session, wrappedBuilder);
ApplicationManager.getApplication().executeOnPooledThread(() -> { if (params instanceof PreLaunchAware pla) {
ProcessTerminatedListener.attach(process.getProcessHandler(), environment.getProject()); ApplicationManager.getApplication().executeOnPooledThread(() -> {
ProcessTerminatedListener.attach(process.getProcessHandler(), environment.getProject());
if (params instanceof PreLaunchAware pla) {
try { try {
pla.preLaunch(); pla.preLaunch();
} catch (Exception e) { } catch (Exception e) {
@ -156,9 +162,9 @@ public abstract class ZigDebugRunnerBase<ProfileState extends ProfileStateBase<?
}); });
return; return;
} }
} process.unSuppress(true);
process.unSuppress(true); });
}); }
process.doStart(); process.doStart();
return process; return process;
} }

View file

@ -16,15 +16,13 @@
package com.falsepattern.zigbrains.debugger.runner.binary; package com.falsepattern.zigbrains.debugger.runner.binary;
import com.falsepattern.zigbrains.debugger.execution.binary.ProfileStateBinary;
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.debugger.execution.binary.ProfileStateBinary;
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain; import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
import com.intellij.execution.ExecutionException; import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
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.val;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.File; import java.io.File;

View file

@ -16,19 +16,16 @@
package com.falsepattern.zigbrains.debugger.runner.binary; package com.falsepattern.zigbrains.debugger.runner.binary;
import com.falsepattern.zigbrains.debugger.execution.binary.ProfileStateBinary;
import com.falsepattern.zigbrains.debugger.execution.binary.ZigExecConfigBinary;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase; import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugRunnerBase; import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugRunnerBase;
import com.falsepattern.zigbrains.project.execution.base.ProfileStateBase; import com.falsepattern.zigbrains.project.execution.base.ProfileStateBase;
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.AbstractZigToolchain;
import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain; import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain;
import com.intellij.execution.ExecutionException; import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.runners.ExecutionEnvironment; 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 com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;

View file

@ -22,23 +22,16 @@ import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugEmitBinaryInstall
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;
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.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.val; import lombok.val;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
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.concurrent.CompletableFuture;
public class ZigDebugParametersBuild extends ZigDebugParametersBase<ProfileStateBuild> implements PreLaunchAware { 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!";

View file

@ -16,21 +16,17 @@
package com.falsepattern.zigbrains.debugger.runner.build; package com.falsepattern.zigbrains.debugger.runner.build;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugRunnerBase;
import com.falsepattern.zigbrains.project.execution.base.ProfileStateBase; import com.falsepattern.zigbrains.project.execution.base.ProfileStateBase;
import com.falsepattern.zigbrains.project.execution.build.ProfileStateBuild; import com.falsepattern.zigbrains.project.execution.build.ProfileStateBuild;
import com.falsepattern.zigbrains.project.execution.build.ZigExecConfigBuild; import com.falsepattern.zigbrains.project.execution.build.ZigExecConfigBuild;
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain; import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain; 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.ExecutionException;
import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.runners.ExecutionEnvironment; 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 com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
import lombok.val;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;

View file

@ -16,7 +16,6 @@
package com.falsepattern.zigbrains.debugger.runner.run; 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.debugger.runner.base.ZigDebugRunnerBase;
import com.falsepattern.zigbrains.project.execution.base.ProfileStateBase; import com.falsepattern.zigbrains.project.execution.base.ProfileStateBase;
import com.falsepattern.zigbrains.project.execution.run.ProfileStateRun; import com.falsepattern.zigbrains.project.execution.run.ProfileStateRun;
@ -26,9 +25,6 @@ import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain;
import com.intellij.execution.ExecutionException; import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.runners.ExecutionEnvironment; 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 com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;

View file

@ -16,10 +16,10 @@
package com.falsepattern.zigbrains.debugger.runner.test; package com.falsepattern.zigbrains.debugger.runner.test;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugEmitBinaryInstaller;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersEmitBinaryBase; import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersEmitBinaryBase;
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.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;

View file

@ -16,19 +16,16 @@
package com.falsepattern.zigbrains.debugger.runner.test; package com.falsepattern.zigbrains.debugger.runner.test;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugRunnerBase;
import com.falsepattern.zigbrains.project.execution.base.ProfileStateBase; import com.falsepattern.zigbrains.project.execution.base.ProfileStateBase;
import com.falsepattern.zigbrains.project.execution.test.ProfileStateTest; import com.falsepattern.zigbrains.project.execution.test.ProfileStateTest;
import com.falsepattern.zigbrains.project.execution.test.ZigExecConfigTest; import com.falsepattern.zigbrains.project.execution.test.ZigExecConfigTest;
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain; import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain; 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.ExecutionException;
import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.runners.ExecutionEnvironment; 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 com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;

View file

@ -0,0 +1,59 @@
package com.falsepattern.zigbrains.debugger.settings;
import com.falsepattern.zigbrains.common.util.dsl.JavaPanel;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.options.ConfigurableUi;
import com.intellij.openapi.options.ConfigurationException;
import lombok.val;
import org.jetbrains.annotations.NotNull;
import javax.swing.JComponent;
import java.util.ArrayList;
import java.util.List;
public class ZigDebuggerGeneralSettingsConfigurableUi implements ConfigurableUi<ZigDebuggerSettings>, Disposable {
private final List<ZigDebuggerUiComponent> components;
public ZigDebuggerGeneralSettingsConfigurableUi() {
components = new ArrayList<>();
components.add(new ZigDebuggerToolchainConfigurableUi());
}
@Override
public boolean isModified(@NotNull ZigDebuggerSettings settings) {
for (val it: components) {
if (it.isModified(settings)) {
return true;
}
}
return false;
}
@Override
public void reset(@NotNull ZigDebuggerSettings settings) {
for (val it: components) {
it.reset(settings);
}
}
@Override
public void apply(@NotNull ZigDebuggerSettings settings) throws ConfigurationException {
for (val it: components) {
it.apply(settings);
}
}
@Override
public @NotNull JComponent getComponent() {
return JavaPanel.newPanel(p -> {
for (val it: components) {
it.buildUi(p);
}
});
}
@Override
public void dispose() {
components.forEach(Disposable::dispose);
}
}

View file

@ -0,0 +1,61 @@
package com.falsepattern.zigbrains.debugger.settings;
import com.falsepattern.zigbrains.ZigBundle;
import com.falsepattern.zigbrains.debugger.toolchain.DebuggerKind;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.SimpleConfigurable;
import com.intellij.util.xmlb.XmlSerializerUtil;
import com.intellij.xdebugger.settings.DebuggerSettingsCategory;
import com.intellij.xdebugger.settings.XDebuggerSettings;
import lombok.val;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class ZigDebuggerSettings extends XDebuggerSettings<ZigDebuggerSettings> {
public static final String GENERAL_SETTINGS_ID = "Debugger.Zig.General";
public DebuggerKind debuggerKind = DebuggerKind.defaultKind();
public boolean downloadAutomatically = false;
public boolean useClion = true;
protected ZigDebuggerSettings() {
super("Zig");
}
@Override
public @Nullable ZigDebuggerSettings getState() {
return this;
}
@Override
public void loadState(@NotNull ZigDebuggerSettings state) {
XmlSerializerUtil.copyBean(state, this);
}
@Override
public @NotNull Collection<? extends Configurable> createConfigurables(@NotNull DebuggerSettingsCategory category) {
val configurable = switch (category) {
case GENERAL -> createGeneralSettingsConfigurable();
default -> null;
};
return configurable == null ? Collections.emptyList() : List.of(configurable);
}
private Configurable createGeneralSettingsConfigurable() {
return SimpleConfigurable.create(
GENERAL_SETTINGS_ID,
ZigBundle.message("settings.debugger.title"),
ZigDebuggerGeneralSettingsConfigurableUi.class,
ZigDebuggerSettings::getInstance
);
}
public static ZigDebuggerSettings getInstance() {
return XDebuggerSettings.getInstance(ZigDebuggerSettings.class);
}
}

View file

@ -0,0 +1,124 @@
package com.falsepattern.zigbrains.debugger.settings;
import com.falsepattern.zigbrains.ZigBundle;
import com.falsepattern.zigbrains.common.util.dsl.JavaPanel;
import com.falsepattern.zigbrains.debugger.toolchain.DebuggerAvailability;
import com.falsepattern.zigbrains.debugger.toolchain.DebuggerKind;
import com.falsepattern.zigbrains.debugger.toolchain.ZigDebuggerToolchainService;
import com.intellij.ide.plugins.PluginManager;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.observable.util.ListenerUiUtil;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.ui.components.JBCheckBox;
import lombok.val;
import org.jetbrains.annotations.NotNull;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JEditorPane;
import java.util.Arrays;
import java.util.Vector;
import static com.intellij.ui.dsl.builder.UtilsKt.DEFAULT_COMMENT_WIDTH;
public class ZigDebuggerToolchainConfigurableUi extends ZigDebuggerUiComponent {
private final ComboBox<DebuggerKind> debuggerKindCombobox = new ComboBox<>(createDebuggerKindComboBoxModel());
private final JBCheckBox downloadAutomaticallyCheckBox = new JBCheckBox(
ZigBundle.message("settings.debugger.toolchain.download.debugger.automatically.checkbox"),
ZigDebuggerSettings.getInstance().downloadAutomatically
);
private final JBCheckBox useClion = new JBCheckBox(
ZigBundle.message("settings.debugger.toolchain.use.clion.toolchains"),
ZigDebuggerSettings.getInstance().useClion
);
private JEditorPane comment = null;
private DebuggerKind currentDebuggerKind() {
return debuggerKindCombobox.getItem();
}
@Override
public boolean isModified(@NotNull ZigDebuggerSettings settings) {
return settings.debuggerKind != debuggerKindCombobox.getItem() ||
settings.downloadAutomatically != downloadAutomaticallyCheckBox.isSelected() ||
settings.useClion != useClion.isSelected();
}
@Override
public void reset(@NotNull ZigDebuggerSettings settings) {
debuggerKindCombobox.setItem(settings.debuggerKind);
downloadAutomaticallyCheckBox.setSelected(settings.downloadAutomatically);
useClion.setSelected(settings.useClion);
}
@Override
public void apply(@NotNull ZigDebuggerSettings settings) throws ConfigurationException {
settings.debuggerKind = debuggerKindCombobox.getItem();
settings.downloadAutomatically = downloadAutomaticallyCheckBox.isSelected();
settings.useClion = useClion.isSelected();
}
@Override
public void buildUi(JavaPanel panel) {
panel.row(ZigBundle.message("settings.debugger.toolchain.debugger.label"), r -> {
comment = r.cell(debuggerKindCombobox)
.comment("", DEFAULT_COMMENT_WIDTH, (e) -> downloadDebugger())
.applyToComponent(c -> {
ListenerUiUtil.whenItemSelected(c, null, (x) -> {
update();
return null;
});
return null;
})
.getComment();
});
panel.row(r -> {
r.cell(downloadAutomaticallyCheckBox);
});
if (PluginManager.isPluginInstalled(PluginId.getId("com.intellij.modules.clion"))) {
panel.row(r -> {
r.cell(useClion);
});
}
update();
}
private ComboBoxModel<DebuggerKind> createDebuggerKindComboBoxModel() {
val toolchainService = ZigDebuggerToolchainService.getInstance();
val availableKinds = Arrays.stream(DebuggerKind.values())
.filter(kind -> toolchainService.debuggerAvailability(kind) != DebuggerAvailability.Unavailable)
.toList();
val model = new DefaultComboBoxModel<>(new Vector<>(availableKinds));
model.setSelectedItem(ZigDebuggerSettings.getInstance().debuggerKind);
return model;
}
private void downloadDebugger() {
val result = ZigDebuggerToolchainService.getInstance().downloadDebugger(null, currentDebuggerKind());
if (result instanceof ZigDebuggerToolchainService.DownloadResult.Ok) {
update();
}
}
private void update() {
val availability = ZigDebuggerToolchainService.getInstance().debuggerAvailability(currentDebuggerKind());
final String text;
if (availability == DebuggerAvailability.NeedToDownload) {
text = ZigBundle.message("settings.debugger.toolchain.download.comment");
} else if (availability == DebuggerAvailability.NeedToUpdate) {
text = ZigBundle.message("settings.debugger.toolchain.update.comment");
} else {
text = null;
}
if (comment != null) {
comment.setText(text);
comment.setVisible(text != null);
}
}
}

View file

@ -0,0 +1,22 @@
package com.falsepattern.zigbrains.debugger.settings;
import com.falsepattern.zigbrains.common.util.dsl.JavaPanel;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.options.ConfigurableUi;
import org.jetbrains.annotations.NotNull;
import javax.swing.JComponent;
public abstract class ZigDebuggerUiComponent implements ConfigurableUi<ZigDebuggerSettings>, Disposable {
public abstract void buildUi(JavaPanel panel);
@Override
public @NotNull JComponent getComponent() {
return JavaPanel.newPanel(this::buildUi);
}
@Override
public void dispose() {
}
}

View file

@ -0,0 +1,81 @@
package com.falsepattern.zigbrains.debugger.toolchain;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.nio.file.Path;
public sealed interface DebuggerAvailability {
enum Kind {
Unavailable,
NeedToDownload,
NeedToUpdate,
Bundled,
Binaries
}
Kind kind();
@NoArgsConstructor(access = AccessLevel.PRIVATE)
final class Unavailable implements DebuggerAvailability {
@Override
public Kind kind() {
return Kind.Unavailable;
}
}
Unavailable Unavailable = new Unavailable();
@NoArgsConstructor(access = AccessLevel.PRIVATE)
final class NeedToDownload implements DebuggerAvailability {
@Override
public Kind kind() {
return Kind.NeedToDownload;
}
}
NeedToDownload NeedToDownload = new NeedToDownload();
@NoArgsConstructor(access = AccessLevel.PRIVATE)
final class NeedToUpdate implements DebuggerAvailability {
@Override
public Kind kind() {
return Kind.NeedToUpdate;
}
}
NeedToUpdate NeedToUpdate = new NeedToUpdate();
@NoArgsConstructor(access = AccessLevel.PRIVATE)
final class Bundled implements DebuggerAvailability {
@Override
public Kind kind() {
return Kind.Bundled;
}
}
Bundled Bundled = new Bundled();
sealed interface Binaries extends DebuggerAvailability {
@Override
default Kind kind() {
return Kind.Binaries;
}
DebuggerKind binariesKind();
}
record LLDBBinaries(Path frameworkFile, Path frontendFile) implements Binaries {
@Override
public DebuggerKind binariesKind() {
return DebuggerKind.LLDB;
}
}
record GDBBinaries(Path gdbFile) implements Binaries {
@Override
public DebuggerKind binariesKind() {
return DebuggerKind.GDB;
}
}
record MSVCBinaries(Path msvcFile) implements Binaries {
@Override
public DebuggerKind binariesKind() {
return DebuggerKind.MSVC;
}
}
}

View file

@ -0,0 +1,15 @@
package com.falsepattern.zigbrains.debugger.toolchain;
import com.intellij.openapi.util.SystemInfo;
public enum DebuggerKind {
LLDB,
GDB,
MSVC;
public static DebuggerKind defaultKind() {
if (SystemInfo.isWindows)
return MSVC;
return LLDB;
}
}

View file

@ -0,0 +1,496 @@
package com.falsepattern.zigbrains.debugger.toolchain;
import com.falsepattern.zigbrains.ZigBundle;
import com.falsepattern.zigbrains.common.ZigPathManager;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.components.Service;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogBuilder;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.ui.BrowserHyperlinkListener;
import com.intellij.ui.HyperlinkLabel;
import com.intellij.ui.components.JBPanel;
import com.intellij.util.download.DownloadableFileService;
import com.intellij.util.io.Decompressor;
import com.intellij.util.system.CpuArch;
import com.intellij.util.system.OS;
import com.jetbrains.cidr.execution.debugger.CidrDebuggerPathManager;
import com.jetbrains.cidr.execution.debugger.backend.bin.UrlProvider;
import com.jetbrains.cidr.execution.debugger.backend.lldb.LLDBDriverConfiguration;
import lombok.AccessLevel;
import lombok.Cleanup;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;
import lombok.val;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicReference;
@Service(Service.Level.APP)
public final class ZigDebuggerToolchainService {
public static ZigDebuggerToolchainService getInstance() {
return ApplicationManager.getApplication().getService(ZigDebuggerToolchainService.class);
}
public DebuggerAvailability debuggerAvailability(DebuggerKind kind) {
return switch (kind) {
case LLDB -> lldbAvailability();
case GDB -> gdbAvailability();
case MSVC -> msvcAvailability();
};
}
public DebuggerAvailability lldbAvailability() {
if (LLDBDriverConfiguration.hasBundledLLDB())
return DebuggerAvailability.Bundled;
final String frameworkPath, frontendPath;
if (SystemInfo.isMac) {
frameworkPath = "LLDB.framework";
frontendPath = "LLDBFrontend";
} else if (SystemInfo.isUnix) {
frameworkPath = "lib/liblldb.so";
frontendPath = "bin/LLDBFrontend";
} else if (SystemInfo.isWindows) {
return DebuggerAvailability.Unavailable;
// frameworkPath = "bin/liblldb.dll";
// frontendPath = "bin/LLDBFrontend.exe";
} else {
return DebuggerAvailability.Unavailable;
}
val lldbPath = lldbPath();
val frameworkFile = lldbPath.resolve(frameworkPath);
val frontendFile = lldbPath.resolve(frontendPath);
if (!Files.exists(frameworkFile) || !Files.exists(frontendFile))
return DebuggerAvailability.NeedToDownload;
val versions = loadDebuggerVersions(DebuggerKind.LLDB);
val urls = lldbUrls();
if (urls == null)
return DebuggerAvailability.Unavailable;
val lldbFrameworkVersion = fileNameWithoutExtension(urls.framework().toString());
val lldbFrontendVersion = fileNameWithoutExtension(urls.frontend().toString());
if (!Objects.equals(versions.get(LLDB_FRAMEWORK_PROPERTY_NAME), lldbFrameworkVersion) ||
!Objects.equals(versions.get(LLDB_FRONTEND_PROPERTY_NAME), lldbFrontendVersion))
return DebuggerAvailability.NeedToUpdate;
return new DebuggerAvailability.LLDBBinaries(frameworkFile, frontendFile);
}
public DebuggerAvailability gdbAvailability() {
// Even if we have bundled GDB, it still doesn't work on macOS for local runs
if (SystemInfo.isMac)
return DebuggerAvailability.Unavailable;
if (CidrDebuggerPathManager.getBundledGDBBinary().exists())
return DebuggerAvailability.Bundled;
final String gdbBinaryPath;
if (SystemInfo.isUnix) {
gdbBinaryPath = "bin/gdb";
} else if (SystemInfo.isWindows) {
return DebuggerAvailability.Unavailable;
// gdbBinaryPath = "bin/gdb.exe";
} else {
return DebuggerAvailability.Unavailable;
}
val gdbFile = gdbPath().resolve(gdbBinaryPath);
if (!Files.exists(gdbFile))
return DebuggerAvailability.NeedToDownload;
val versions = loadDebuggerVersions(DebuggerKind.GDB);
val gdbUrl = gdbUrl();
if (gdbUrl == null)
return DebuggerAvailability.Unavailable;
val gdbVersion = fileNameWithoutExtension(gdbUrl.toString());
if (!Objects.equals(versions.get(GDB_PROPERTY_NAME), gdbVersion))
return DebuggerAvailability.NeedToUpdate;
return new DebuggerAvailability.GDBBinaries(gdbFile);
}
public DebuggerAvailability msvcAvailability() {
//Only applies to Windows
if (!SystemInfo.isWindows)
return DebuggerAvailability.Unavailable;
val msvcBinaryPath = "vsdbg.exe";
val msvcFile = msvcPath().resolve(msvcBinaryPath);
if (!Files.exists(msvcFile))
return DebuggerAvailability.NeedToDownload;
val msvcUrl = msvcUrl();
if (msvcUrl == null) //Fallback in case falsepattern.com goes down
return new DebuggerAvailability.MSVCBinaries(msvcFile);
val versions = loadDebuggerVersions(DebuggerKind.MSVC);
if (!Objects.equals(versions.get(MSVC_PROPERTY_NAME), msvcUrl.version))
return DebuggerAvailability.NeedToUpdate;
return new DebuggerAvailability.MSVCBinaries(msvcFile);
}
@SneakyThrows
public DownloadResult downloadDebugger(@Nullable Project project, DebuggerKind debuggerKind) {
val result = ProgressManager.getInstance()
.runProcessWithProgressSynchronously(() -> downloadDebuggerSynchronously(debuggerKind),
ZigBundle.message("dialog.title.download.debugger"),
true,
project);
if (result instanceof DownloadResult.Ok) {
Notifications.Bus.notify(new Notification(
"ZigBrains.Debugger.Warn",
ZigBundle.message("notification.title.debugger"),
ZigBundle.message("notification.content.debugger.successfully.downloaded"),
NotificationType.INFORMATION
));
} else if (result instanceof DownloadResult.Failed) {
Notifications.Bus.notify(new Notification(
"ZigBrains.Project",
ZigBundle.message("notification.title.debugger"),
ZigBundle.message("notification.content.debugger.downloading.failed"),
NotificationType.ERROR
));
}
return result;
}
private DownloadResult downloadDebuggerSynchronously(DebuggerKind kind) {
val baseDir = basePath(kind);
val downloadableBinaries = switch (kind) {
case LLDB -> {
val urls = lldbUrls();
if (urls == null)
yield null;
val fwUrl = urls.framework.toString();
val feUrl = urls.frontend.toString();
yield List.of(
new DownloadableDebuggerBinary(fwUrl, LLDB_FRAMEWORK_PROPERTY_NAME, fileNameWithoutExtension(fwUrl)),
new DownloadableDebuggerBinary(feUrl, LLDB_FRONTEND_PROPERTY_NAME, fileNameWithoutExtension(feUrl))
);
}
case GDB -> {
val gdbUrl = gdbUrl();
if (gdbUrl == null)
yield null;
val url = gdbUrl.toString();
yield List.of(new DownloadableDebuggerBinary(url, GDB_PROPERTY_NAME, fileNameWithoutExtension(url)));
}
case MSVC -> {
val msvcUrl = msvcUrl();
if (msvcUrl == null)
yield null;
AtomicReference<Boolean> accepted = new AtomicReference<>(false);
ApplicationManager.getApplication().invokeAndWait(() -> {
val dialog = new DialogBuilder();
dialog.setTitle(msvcUrl.dialogTitle);
dialog.addCancelAction().setText("Reject");
dialog.addOkAction().setText("Accept");
val centerPanel = new JBPanel<>();
val hyperlink = new HyperlinkLabel();
hyperlink.setTextWithHyperlink(msvcUrl.dialogBody);
hyperlink.setHyperlinkTarget(msvcUrl.dialogLink);
hyperlink.addHyperlinkListener(new BrowserHyperlinkListener());
centerPanel.add(hyperlink);
dialog.centerPanel(centerPanel);
accepted.set(dialog.showAndGet());
});
if (!accepted.get())
yield null;
yield List.of(new DownloadableDebuggerBinary(msvcUrl.url.toString(), MSVC_PROPERTY_NAME, msvcUrl.version, "extension/debugAdapters/vsdbg/bin"));
}
};
if (downloadableBinaries == null)
return DownloadResult.NoUrls;
try {
downloadAndUnarchive(baseDir, downloadableBinaries);
return new DownloadResult.Ok(baseDir);
} catch (IOException e) {
//TODO logging
e.printStackTrace();
return new DownloadResult.Failed(e.getMessage());
}
}
private void downloadAndUnarchive(Path baseDir, List<DownloadableDebuggerBinary> binariesToDownload)
throws IOException {
val service = DownloadableFileService.getInstance();
val downloadDir = baseDir.toFile();
FileUtil.deleteRecursively(baseDir);
val descriptions = binariesToDownload.stream().map(it -> service.createFileDescription(it.url, fileName(it.url))).toList();
val downloader = service.createDownloader(descriptions, "Debugger downloading");
val downloadDirectory = downloadPath().toFile();
val downloadResults = downloader.download(downloadDirectory);
val versions = new Properties();
for (val result: downloadResults) {
val downloadUrl = result.getSecond().getDownloadUrl();
val binaryToDownload = binariesToDownload.stream()
.filter(it -> Objects.equals(it.url, downloadUrl))
.findFirst()
.orElseThrow(() -> new IOException("Failed to find matching download URL!"));
val propertyName = binaryToDownload.propertyName;
val archiveFile = result.getFirst();
Unarchiver.unarchive(archiveFile, downloadDir, binaryToDownload.prefix);
archiveFile.delete();
versions.put(propertyName, binaryToDownload.version);
}
saveVersionsFile(baseDir, versions);
}
public Properties loadDebuggerVersions(DebuggerKind kind) {
return loadVersions(basePath(kind));
}
public void saveDebuggerVersions(DebuggerKind kind, Properties versions) {
saveVersionsFile(basePath(kind), versions);
}
private void saveVersionsFile(Path basePath, Properties versions) {
val file = basePath.resolve(DEBUGGER_VERSIONS);
try (val writer = Files.newBufferedWriter(file)){
versions.store(writer, "");
} catch (IOException e) {
//TODO logging
e.printStackTrace();
}
}
private Properties loadVersions(Path basePath) {
val versions = new Properties();
val versionsFile = basePath.resolve(DEBUGGER_VERSIONS);
if (Files.exists(versionsFile)) {
try(val reader = Files.newBufferedReader(versionsFile)) {
versions.load(reader);
} catch (IOException e) {
//TODO logging
e.printStackTrace();
}
}
return versions;
}
private Path basePath(DebuggerKind kind) {
return switch (kind) {
case LLDB -> lldbPath();
case GDB -> gdbPath();
case MSVC -> msvcPath();
};
}
private static Path downloadPath() {
return Paths.get(PathManager.getTempPath());
}
private static Path lldbPath() {
return ZigPathManager.pluginDirInSystem().resolve("lldb");
}
private static Path gdbPath() {
return ZigPathManager.pluginDirInSystem().resolve("gdb");
}
private static Path msvcPath() {
return ZigPathManager.pluginDirInSystem().resolve("msvc");
}
private LLDBUrls lldbUrls() {
val lldb = UrlProvider.lldb(OS.CURRENT, CpuArch.CURRENT);
if (lldb == null)
return null;
val lldbFrontend = UrlProvider.lldbFrontend(OS.CURRENT, CpuArch.CURRENT);
if (lldbFrontend == null)
return null;
return new LLDBUrls(lldb, lldbFrontend);
}
private record LLDBUrls(URL framework, URL frontend) {}
private URL gdbUrl() {
return UrlProvider.gdb(OS.CURRENT, CpuArch.CURRENT);
}
private Properties msvcProperties() {
val service = DownloadableFileService.getInstance();
val desc = service.createFileDescription("https://falsepattern.com/zigbrains/msvc.properties", "msvc.properties");
val downloader = service.createDownloader(List.of(desc), "Debugger metadata downloading");
val downloadDirectory = downloadPath().toFile();
val prop = new Properties();
try {
val downloadResults = downloader.download(downloadDirectory);
for (val result : downloadResults) {
if (Objects.equals(result.second.getDefaultFileName(), "msvc.properties")) {
@Cleanup val reader = new FileReader(result.first);
prop.load(reader);
}
}
} catch (IOException e) {
//TODO logging
e.printStackTrace();
Notifications.Bus.notify(new Notification(
"Zig Debugger",
ZigBundle.message("notification.title.debugger"),
ZigBundle.message("notification.content.debugger.metadata.downloading.failed"),
NotificationType.ERROR
));
}
return prop;
}
private MSVCUrl msvcUrl() {
String dlKey = switch (CpuArch.CURRENT) {
case X86 -> "downloadX86";
case X86_64 -> "downloadX86_64";
case ARM64 -> "downloadARM64";
default -> null;
};
if (dlKey == null)
return null;
val props = msvcProperties();
val version = props.getProperty("version");
val url = props.getProperty(dlKey);
if (url == null || version == null)
return null;
try {
return new MSVCUrl(new URL(url), version, props.getProperty("dialogTitle"), props.getProperty("dialogBody"), props.getProperty("dialogLink"));
} catch (MalformedURLException e) {
//TODO logging
e.printStackTrace();
return null;
}
}
private record MSVCUrl(URL url, String version, String dialogTitle, String dialogBody, String dialogLink) {}
private static String fileName(String url) {
return url.substring(url.lastIndexOf('/') + 1);
}
private static String fileNameWithoutExtension(String url) {
url = fileName(url);
url = removeSuffix(url, ".zip");
url = removeSuffix(url, ".tar.gz");
return url;
}
private static String removeSuffix(String str, String suffix) {
if (str.endsWith(suffix))
str = str.substring(0, str.length() - suffix.length());
return str;
}
private static final String DEBUGGER_VERSIONS = "versions.properties";
private static final String LLDB_FRONTEND_PROPERTY_NAME = "lldbFrontend";
private static final String LLDB_FRAMEWORK_PROPERTY_NAME = "lldbFramework";
private static final String GDB_PROPERTY_NAME = "gdb";
private static final String MSVC_PROPERTY_NAME = "msvc";
public sealed interface DownloadResult {
record Ok(Path baseDir) implements DownloadResult {}
@NoArgsConstructor(access = AccessLevel.PRIVATE)
final class NoUrls implements DownloadResult {}
NoUrls NoUrls = new NoUrls();
record Failed(String message) implements DownloadResult {}
}
private enum Unarchiver {
ZIP {
@Override
protected String extension() {
return "zip";
}
@Override
protected Decompressor createDecompressor(File file) {
return new Decompressor.Zip(file);
}
},
TAR {
@Override
protected String extension() {
return "tar.gz";
}
@Override
protected Decompressor createDecompressor(File file) {
return new Decompressor.Tar(file);
}
},
VSIX {
@Override
protected String extension() {
return "vsix";
}
@Override
protected Decompressor createDecompressor(File file) {
return new Decompressor.Zip(file);
}
};
protected abstract String extension();
protected abstract Decompressor createDecompressor(File file);
static void unarchive(File archivePath, File dst, String prefix) throws IOException {
val unarchiver = Arrays.stream(values())
.filter(it -> archivePath.getName().endsWith(it.extension()))
.findFirst()
.orElseThrow(() -> new IOException("Failed to find decompressor for file " + archivePath.getName()));
val dec = unarchiver.createDecompressor(archivePath);
if (prefix != null) {
dec.removePrefixPath(prefix);
}
dec.extract(dst);
}
}
private record DownloadableDebuggerBinary(String url, String propertyName, String version, String prefix) {
public DownloadableDebuggerBinary(String url, String propertyName, String version) {
this(url, propertyName, version, null);
}
}
}

View file

@ -0,0 +1,56 @@
/*
* 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.win;
import com.falsepattern.zigbrains.debugger.dap.DAPDebuggerDriverConfiguration;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.jetbrains.cidr.ArchitectureType;
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriver;
import lombok.val;
import org.eclipse.lsp4j.debug.InitializeRequestArguments;
import org.jetbrains.annotations.NotNull;
import java.nio.file.Path;
public abstract class MSVCDriverConfiguration extends DAPDebuggerDriverConfiguration {
protected abstract Path getDebuggerExecutable();
@Override
public @NotNull DebuggerDriver createDriver(DebuggerDriver.@NotNull Handler handler, @NotNull ArchitectureType architectureType)
throws ExecutionException {
return new WinDAPDriver(handler, this);
}
@Override
public @NotNull GeneralCommandLine createDriverCommandLine(
@NotNull DebuggerDriver debuggerDriver, @NotNull ArchitectureType architectureType)
throws ExecutionException {
val path = getDebuggerExecutable();
val cli = new GeneralCommandLine();
cli.setExePath(path.toString());
cli.addParameters("--interpreter=vscode", "--extConfigDir=%USERPROFILE%\\.cppvsdbg\\extensions");
cli.setWorkDirectory(path.getParent().toString());
return cli;
}
@Override
public void customizeInitializeArguments(InitializeRequestArguments initArgs) {
initArgs.setPathFormat("path");
initArgs.setAdapterID("cppvsdbg");
}
}

View file

@ -16,6 +16,7 @@
package com.falsepattern.zigbrains.debugger.win; package com.falsepattern.zigbrains.debugger.win;
import com.falsepattern.zigbrains.debugger.dap.DAPDebuggerDriverConfiguration;
import com.falsepattern.zigbrains.debugger.dap.DAPDriver; import com.falsepattern.zigbrains.debugger.dap.DAPDriver;
import com.falsepattern.zigbrains.debugger.dap.WrappedDebugServer; import com.falsepattern.zigbrains.debugger.dap.WrappedDebugServer;
import com.intellij.execution.ExecutionException; import com.intellij.execution.ExecutionException;
@ -51,7 +52,7 @@ public class WinDAPDriver extends DAPDriver<
WinDAPDriver.WinDAPDebuggerClient WinDAPDriver.WinDAPDebuggerClient
> { > {
private final CompletableFuture<HandshakeResponse> handshakeFuture = new CompletableFuture<>(); private final CompletableFuture<HandshakeResponse> handshakeFuture = new CompletableFuture<>();
public WinDAPDriver(@NotNull Handler handler, WinDebuggerDriverConfiguration config) throws ExecutionException { public WinDAPDriver(@NotNull Handler handler, DAPDebuggerDriverConfiguration config) throws ExecutionException {
super(handler, config); super(handler, config);
DAPDriver$postConstructor(); DAPDriver$postConstructor();
} }

View file

@ -1,139 +0,0 @@
/*
* 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.win;
import com.falsepattern.zigbrains.debugger.dap.DAPDebuggerDriverConfiguration;
import com.falsepattern.zigbrains.debugger.win.config.WinDebuggerConfigService;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.jetbrains.cidr.ArchitectureType;
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriver;
import lombok.val;
import org.apache.commons.io.file.PathUtils;
import org.eclipse.lsp4j.debug.InitializeRequestArguments;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.lang.ref.Cleaner;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Map;
public class WinDebuggerDriverConfiguration extends DAPDebuggerDriverConfiguration {
private static void extractVSDebugger(Path pathToPluginFile, Path pathToExtracted) throws IOException {
if (pathToPluginFile == null) {
throw new IllegalArgumentException("Please set the debugger inside Build, Execution, Deployment | Debugger | Zig (Windows)");
}
if (!Files.isRegularFile(pathToPluginFile) || !pathToPluginFile.getFileName().toString().endsWith(".vsix")) {
throw new IllegalArgumentException("Invalid debugger file path! Please check Build, Execution, Deployment | Debugger | Zig (Windows) again! The file MUST be a .vsix file!");
}
URI uri;
try {
uri = new URI("jar:" + pathToPluginFile.toAbsolutePath().toUri().toASCIIString());
} catch (URISyntaxException e) {
throw new IllegalArgumentException("Could not parse plugin file path: " + pathToPluginFile);
}
try (val fs = FileSystems.newFileSystem(uri, Map.of())) {
val basePath = fs.getPath("/extension/debugAdapters/vsdbg/bin");
try (val walk = Files.walk(basePath)) {
walk.forEach(path -> {
if (!Files.isRegularFile(path))
return;
val relPath = Path.of(basePath.relativize(path).toString());
val resPath = pathToExtracted.resolve(relPath);
try {
Files.createDirectories(resPath.getParent());
Files.copy(path, resPath, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
}
}
@Override
public @NotNull GeneralCommandLine createDriverCommandLine(@NotNull DebuggerDriver debuggerDriver, @NotNull ArchitectureType architectureType) {
val pathToPluginFileStr = WinDebuggerConfigService.getInstance().cppToolsPath;
if (pathToPluginFileStr == null || pathToPluginFileStr.isBlank()) {
throw new IllegalArgumentException("Please set the debugger inside Build, Execution, Deployment | Debugger | Zig (Windows)");
}
Path pathToPluginFile;
try {
pathToPluginFile = Path.of(pathToPluginFileStr);
} catch (InvalidPathException e) {
throw new IllegalArgumentException("Invalid debugger path " + pathToPluginFileStr + "! Make sure it points to the .vsix file!");
}
Path pathToExtracted;
try {
val tmpDir = Path.of(System.getProperty("java.io.tmpdir"));
int i = 0;
do {
pathToExtracted = tmpDir.resolve("zb-windbg-" + i++);
} while (Files.exists(pathToExtracted.resolve(".lock")) || Files.isRegularFile(pathToExtracted));
if (Files.exists(pathToExtracted)) {
PathUtils.deleteDirectory(pathToExtracted);
}
extractVSDebugger(pathToPluginFile, pathToExtracted);
} catch (IOException e) {
throw new RuntimeException(e);
}
Path finalPathToExtracted = pathToExtracted;
val lockFile = finalPathToExtracted.resolve(".lock");
try {
Files.createFile(lockFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
Cleaner.create().register(debuggerDriver, () -> {
try {
Files.delete(lockFile);
} catch (IOException e) {
e.printStackTrace();
}
});
val cli = new GeneralCommandLine();
cli.setExePath(finalPathToExtracted.resolve("vsdbg.exe").toString());
cli.setCharset(StandardCharsets.UTF_8);
cli.addParameters("--interpreter=vscode", "--extConfigDir=%USERPROFILE%\\.cppvsdbg\\extensions");
cli.setWorkDirectory(finalPathToExtracted.toString());
return cli;
}
@Override
public @NotNull String getDriverName() {
return "WinDAPDriver";
}
@Override
public @NotNull DebuggerDriver createDriver(DebuggerDriver.@NotNull Handler handler, @NotNull ArchitectureType architectureType)
throws ExecutionException {
return new WinDAPDriver(handler, this);
}
@Override
public void customizeInitializeArguments(InitializeRequestArguments initArgs) {
initArgs.setPathFormat("path");
initArgs.setAdapterID("cppvsdbg");
}
}

View file

@ -1,46 +0,0 @@
/*
* 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.win.config;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.Service;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.util.xmlb.XmlSerializerUtil;
import org.jetbrains.annotations.NotNull;
@Service(Service.Level.APP)
@State(name = "CPPToolsSettings",
storages = @Storage("zigbrains.xml"))
public final class WinDebuggerConfigService implements PersistentStateComponent<WinDebuggerConfigService> {
public String cppToolsPath = "";
public static WinDebuggerConfigService getInstance() {
return ApplicationManager.getApplication().getService(WinDebuggerConfigService.class);
}
@Override
public @NotNull WinDebuggerConfigService getState() {
return this;
}
@Override
public void loadState(@NotNull WinDebuggerConfigService state) {
XmlSerializerUtil.copyBean(state, this);
}
}

View file

@ -1,88 +0,0 @@
/*
* 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.win.config;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.NlsContexts;
import com.intellij.ui.JBColor;
import com.intellij.util.system.OS;
import lombok.val;
import org.jetbrains.annotations.Nullable;
import javax.swing.JComponent;
import java.util.Objects;
import static com.intellij.ui.dsl.builder.BuilderKt.panel;
public class WinDebuggerConfigurable implements Configurable {
private WinDebuggerSettingsPanel settingsPanel;
@Override
public @NlsContexts.ConfigurableName String getDisplayName() {
return "Zig Debugger (Windows)";
}
@Override
public @Nullable JComponent createComponent() {
settingsPanel = new WinDebuggerSettingsPanel();
return panel((p) -> {
if (OS.CURRENT != OS.Windows) {
p.row("This menu has no effect on linux/macos/non-windows systems, use the C++ toolchains (see plugin description).", (r) -> null);
p.row("For completeness' sake, here is what you would need to configure on Windows:", (r) -> null);
p.separator(JBColor.foreground());
}
settingsPanel.attachPanelTo(p);
return null;
});
}
@Override
public boolean isModified() {
if (settingsPanel == null)
return false;
var cppSettings = WinDebuggerConfigService.getInstance();
var settingsData = settingsPanel.getData();
return !Objects.equals(settingsData.cppToolsPath(), cppSettings.cppToolsPath);
}
@Override
public void apply() throws ConfigurationException {
if (settingsPanel == null)
return;
var cppSettings = WinDebuggerConfigService.getInstance();
var settingsData = settingsPanel.getData();
cppSettings.cppToolsPath = settingsData.cppToolsPath();
}
@Override
public void reset() {
if (settingsPanel == null)
return;
val cppSettings = WinDebuggerConfigService.getInstance();
settingsPanel.setData(new WinDebuggerSettingsPanel.SettingsData(cppSettings.cppToolsPath));
}
@Override
public void disposeUIResources() {
if (settingsPanel == null)
return;
Disposer.dispose(settingsPanel);
settingsPanel = null;
}
}

View file

@ -1,99 +0,0 @@
/*
* 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.win.config;
import com.falsepattern.zigbrains.common.util.StringUtil;
import com.falsepattern.zigbrains.common.util.TextFieldUtil;
import com.falsepattern.zigbrains.project.openapi.MyDisposable;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.Disposer;
import com.intellij.ui.HyperlinkLabel;
import com.intellij.ui.dsl.builder.AlignX;
import com.intellij.ui.dsl.builder.AlignY;
import com.intellij.ui.dsl.builder.Panel;
import lombok.Getter;
import lombok.val;
import org.jetbrains.annotations.Nullable;
import javax.swing.JLabel;
import java.util.Optional;
public class WinDebuggerSettingsPanel implements MyDisposable {
@Getter
private boolean disposed = false;
public record SettingsData(@Nullable String cppToolsPath) {}
@SuppressWarnings("DialogTitleCapitalization")
private final TextFieldWithBrowseButton pathToArchive = TextFieldUtil.pathToFileTextField(this,
"Path to \"cpptools-win**.vsix\"",
() -> {});
public SettingsData getData() {
return new SettingsData(StringUtil.blankToNull(pathToArchive.getText()));
}
public void setData(SettingsData value) {
pathToArchive.setText(Optional.ofNullable(value.cppToolsPath()).orElse(""));
}
private static HyperlinkLabel link(String url) {
val href = new HyperlinkLabel(url);
href.setHyperlinkTarget(url);
return href;
}
public void attachPanelTo(Panel panel) {
panel.panel(p -> {
p.row("Debugging Zig on Windows requires you to manually install the MSVC toolchain.",
(r) -> null);
p.row("To install the MSVC debugger, follow setup 3 under Prerequisites on the following page:",
(r) -> null);
return null;
});
panel.panel(p -> {
p.row((JLabel) null, (r) -> {
r.cell(link("https://code.visualstudio.com/docs/cpp/config-msvc"));
return null;
});
return null;
});
panel.panel(p -> {
p.row("After you've installed MSVC, you also need download the vscode plugin with the debugger adapter.", (r) -> null);
p.row("Latest known working version: 1.19.6. Newer versions may or may not work.", (r) -> null);
return null;
});
panel.panel(p -> {
p.row("You can download the latest version here:", (r) -> {
r.cell(link("https://github.com/microsoft/vscode-cpptools/releases"));
return null;
});
p.row("Put the path to the downloaded file here:", (r) -> {
r.cell(pathToArchive).resizableColumn().align(AlignX.FILL).align(AlignY.FILL);
return null;
});
return null;
});
}
@Override
public void dispose() {
disposed = true;
Disposer.dispose(pathToArchive);
}
}

View file

@ -14,10 +14,12 @@
~ limitations under the License. ~ limitations under the License.
--> -->
<idea-plugin package="com.falsepattern.zigbrains.cpp"> <idea-plugin package="com.falsepattern.zigbrains.clion">
<depends>com.intellij.modules.clion</depends> <depends>com.intellij.modules.clion</depends>
<extensions defaultExtensionNs="com.falsepattern.zigbrains"> <extensions defaultExtensionNs="com.falsepattern.zigbrains">
<debuggerDriverProvider implementation="com.falsepattern.zigbrains.cpp.CPPDebuggerDriverProvider"/> <debuggerDriverProvider id="ZigClionDebuggerDriverConfiguration"
implementation="com.falsepattern.zigbrains.clion.ZigClionDebuggerDriverConfigurationProvider"
order="before ZigDefaultDebuggerDriverConfigurationProvider"/>
</extensions> </extensions>
</idea-plugin> </idea-plugin>

View file

@ -16,7 +16,6 @@
<idea-plugin package="com.falsepattern.zigbrains.debugger"> <idea-plugin package="com.falsepattern.zigbrains.debugger">
<depends>com.intellij.modules.cidr.debugger</depends> <depends>com.intellij.modules.cidr.debugger</depends>
<resource-bundle>zigbrains.debugger.Bundle</resource-bundle>
<extensions defaultExtensionNs="com.intellij"> <extensions defaultExtensionNs="com.intellij">
<configurationType implementation="com.falsepattern.zigbrains.debugger.execution.binary.ConfigTypeBinary"/> <configurationType implementation="com.falsepattern.zigbrains.debugger.execution.binary.ConfigTypeBinary"/>
@ -30,21 +29,27 @@
<programRunner implementation="com.falsepattern.zigbrains.debugger.runner.binary.ZigDebugRunnerBinary" <programRunner implementation="com.falsepattern.zigbrains.debugger.runner.binary.ZigDebugRunnerBinary"
id="ZigDebugRunnerBinary"/> id="ZigDebugRunnerBinary"/>
<xdebugger.settings implementation="com.falsepattern.zigbrains.debugger.settings.ZigDebuggerSettings"/>
<notificationGroup displayType="BALLOON" <notificationGroup displayType="BALLOON"
bundle="zigbrains.debugger.Bundle" bundle="zigbrains.Bundle"
key="notif-debug-error" key="notif-debug-info"
id="ZigBrains.Debugger.Error"/> id="ZigBrains.Debugger.Info"/>
<notificationGroup displayType="BALLOON" <notificationGroup displayType="BALLOON"
bundle="zigbrains.debugger.Bundle" bundle="zigbrains.Bundle"
key="notif-debug-warn" key="notif-debug-warn"
id="ZigBrains.Debugger.Warn"/> id="ZigBrains.Debugger.Warn"/>
<applicationConfigurable parentId="project.propDebugger" <notificationGroup displayType="BALLOON"
instance="com.falsepattern.zigbrains.debugger.win.config.WinDebuggerConfigurable" bundle="zigbrains.Bundle"
displayName="Zig (Windows)"/> key="notif-debug-error"
id="ZigBrains.Debugger.Error"/>
</extensions> </extensions>
<extensions defaultExtensionNs="com.falsepattern.zigbrains"> <extensions defaultExtensionNs="com.falsepattern.zigbrains">
<featureProvider implementation="com.falsepattern.zigbrains.debugger.DebuggerFeatures"/> <featureProvider implementation="com.falsepattern.zigbrains.debugger.DebuggerFeatures"/>
<debuggerDriverProvider id="ZigDefaultDebuggerDriverConfigurationProvider"
implementation="com.falsepattern.zigbrains.debugger.ZigDefaultDebuggerDriverConfigurationProvider"
order="last"/>
</extensions> </extensions>
<extensions defaultExtensionNs="cidr.debugger"> <extensions defaultExtensionNs="cidr.debugger">

View file

@ -1,2 +0,0 @@
notif-debug-warn=ZigBrains debugger warning
notif-debug-error=ZigBrains debugger error

View file

@ -32,7 +32,6 @@ import org.jdom.Element;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.nio.file.Path;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;

View file

@ -36,7 +36,8 @@ import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static com.falsepattern.zigbrains.project.execution.base.ZigConfigEditor.*; import static com.falsepattern.zigbrains.project.execution.base.ZigConfigEditor.ZigConfigurable;
import static com.falsepattern.zigbrains.project.execution.base.ZigConfigEditor.coloredConfigurable;
@Getter @Getter
public class ZigExecConfigBuild extends ZigExecConfigBase<ZigExecConfigBuild> { public class ZigExecConfigBuild extends ZigExecConfigBase<ZigExecConfigBuild> {

View file

@ -16,36 +16,21 @@
package com.falsepattern.zigbrains.project.ide.newproject; package com.falsepattern.zigbrains.project.ide.newproject;
import com.falsepattern.zigbrains.project.ide.newproject.ZigProjectConfigurationData;
import com.falsepattern.zigbrains.project.ide.newproject.ZigProjectGeneratorPeer;
import com.falsepattern.zigbrains.project.ide.project.ZigDefaultTemplate;
import com.falsepattern.zigbrains.project.ide.newproject.ZigProjectSettingsStep;
import com.falsepattern.zigbrains.project.openapi.components.ZigProjectSettingsService;
import com.falsepattern.zigbrains.zig.Icons; import com.falsepattern.zigbrains.zig.Icons;
import com.falsepattern.zigbrains.zig.settings.ZLSProjectSettingsService;
import com.intellij.facet.ui.ValidationResult; import com.intellij.facet.ui.ValidationResult;
import com.intellij.ide.util.projectWizard.AbstractNewProjectStep; import com.intellij.ide.util.projectWizard.AbstractNewProjectStep;
import com.intellij.ide.util.projectWizard.CustomStepProjectGenerator; import com.intellij.ide.util.projectWizard.CustomStepProjectGenerator;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.module.Module; import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.NlsContexts; import com.intellij.openapi.util.NlsContexts;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.impl.welcomeScreen.AbstractActionWithPanel; import com.intellij.openapi.wm.impl.welcomeScreen.AbstractActionWithPanel;
import com.intellij.platform.DirectoryProjectGenerator; import com.intellij.platform.DirectoryProjectGenerator;
import com.intellij.platform.ProjectGeneratorPeer; import com.intellij.platform.ProjectGeneratorPeer;
import com.intellij.util.ResourceUtil;
import lombok.val;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import javax.swing.Icon; import javax.swing.Icon;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class ZigDirectoryProjectGenerator implements DirectoryProjectGenerator<ZigProjectConfigurationData>, public class ZigDirectoryProjectGenerator implements DirectoryProjectGenerator<ZigProjectConfigurationData>,
CustomStepProjectGenerator<ZigProjectConfigurationData> { CustomStepProjectGenerator<ZigProjectConfigurationData> {

View file

@ -24,19 +24,15 @@ import com.falsepattern.zigbrains.zig.settings.ZLSSettingsPanel;
import com.intellij.openapi.Disposable; import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.ActionToolbarPosition; import com.intellij.openapi.actionSystem.ActionToolbarPosition;
import com.intellij.ui.ColoredListCellRenderer; import com.intellij.ui.ColoredListCellRenderer;
import com.intellij.ui.JBColor;
import com.intellij.ui.ToolbarDecorator; import com.intellij.ui.ToolbarDecorator;
import com.intellij.ui.components.JBCheckBox; import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBList; import com.intellij.ui.components.JBList;
import com.intellij.ui.dsl.builder.AlignX; import com.intellij.ui.dsl.builder.AlignX;
import com.intellij.ui.dsl.builder.AlignY; import com.intellij.ui.dsl.builder.AlignY;
import com.intellij.ui.dsl.builder.Panel;
import com.intellij.util.ui.JBUI; import com.intellij.util.ui.JBUI;
import lombok.val;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import javax.swing.DefaultListModel; import javax.swing.DefaultListModel;
import javax.swing.JLabel;
import javax.swing.JList; import javax.swing.JList;
import javax.swing.ListSelectionModel; import javax.swing.ListSelectionModel;
import java.util.Arrays; import java.util.Arrays;

View file

@ -16,14 +16,12 @@
package com.falsepattern.zigbrains.project.ide.newproject; package com.falsepattern.zigbrains.project.ide.newproject;
import com.falsepattern.zigbrains.common.util.FileUtil;
import com.falsepattern.zigbrains.zig.Icons; import com.falsepattern.zigbrains.zig.Icons;
import com.intellij.ide.wizard.AbstractNewProjectWizardStep; import com.intellij.ide.wizard.AbstractNewProjectWizardStep;
import com.intellij.ide.wizard.GitNewProjectWizardData; import com.intellij.ide.wizard.GitNewProjectWizardData;
import com.intellij.ide.wizard.NewProjectWizardStep; import com.intellij.ide.wizard.NewProjectWizardStep;
import com.intellij.ide.wizard.language.LanguageGeneratorNewProjectWizard; import com.intellij.ide.wizard.language.LanguageGeneratorNewProjectWizard;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootModificationUtil;
import com.intellij.ui.dsl.builder.AlignX; import com.intellij.ui.dsl.builder.AlignX;
import com.intellij.ui.dsl.builder.Panel; import com.intellij.ui.dsl.builder.Panel;
import lombok.val; import lombok.val;

View file

@ -16,21 +16,18 @@
package com.falsepattern.zigbrains.project.ide.newproject; package com.falsepattern.zigbrains.project.ide.newproject;
import com.falsepattern.zigbrains.common.util.ApplicationUtil;
import com.falsepattern.zigbrains.project.ide.project.ZigDefaultTemplate; import com.falsepattern.zigbrains.project.ide.project.ZigDefaultTemplate;
import com.falsepattern.zigbrains.project.ide.project.ZigProjectTemplate; import com.falsepattern.zigbrains.project.ide.project.ZigProjectTemplate;
import com.falsepattern.zigbrains.project.openapi.components.ZigProjectSettings; import com.falsepattern.zigbrains.project.openapi.components.ZigProjectSettings;
import com.falsepattern.zigbrains.project.openapi.components.ZigProjectSettingsService; import com.falsepattern.zigbrains.project.openapi.components.ZigProjectSettingsService;
import com.falsepattern.zigbrains.zig.settings.ZLSProjectSettingsService; import com.falsepattern.zigbrains.zig.settings.ZLSProjectSettingsService;
import com.falsepattern.zigbrains.zig.settings.ZLSSettings; import com.falsepattern.zigbrains.zig.settings.ZLSSettings;
import com.intellij.ide.wizard.GitNewProjectWizardData;
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;
import com.intellij.openapi.GitRepositoryInitializer; import com.intellij.openapi.GitRepositoryInitializer;
import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
@ -41,7 +38,6 @@ import org.jetbrains.annotations.NotNull;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
public record ZigProjectConfigurationData(boolean git, ZigProjectSettings projConf, ZLSSettings zlsConf, ZigProjectTemplate selectedTemplate) { public record ZigProjectConfigurationData(boolean git, ZigProjectSettings projConf, ZLSSettings zlsConf, ZigProjectTemplate selectedTemplate) {

View file

@ -16,7 +16,6 @@
package com.falsepattern.zigbrains.project.ide.newproject; package com.falsepattern.zigbrains.project.ide.newproject;
import com.falsepattern.zigbrains.project.ide.newproject.ZigProjectConfigurationData;
import com.intellij.ide.util.projectWizard.AbstractNewProjectStep; import com.intellij.ide.util.projectWizard.AbstractNewProjectStep;
import com.intellij.ide.util.projectWizard.ProjectSettingsStepBase; import com.intellij.ide.util.projectWizard.ProjectSettingsStepBase;
import com.intellij.platform.DirectoryProjectGenerator; import com.intellij.platform.DirectoryProjectGenerator;

View file

@ -17,9 +17,7 @@
package com.falsepattern.zigbrains.project.openapi.components; package com.falsepattern.zigbrains.project.openapi.components;
import com.falsepattern.zigbrains.common.WrappingStateComponent; import com.falsepattern.zigbrains.common.WrappingStateComponent;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.util.xmlb.XmlSerializerUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public abstract class AbstractZigProjectSettingsService<T> extends WrappingStateComponent<T> { public abstract class AbstractZigProjectSettingsService<T> extends WrappingStateComponent<T> {

View file

@ -16,18 +16,13 @@
package com.falsepattern.zigbrains.project.openapi.components; package com.falsepattern.zigbrains.project.openapi.components;
import com.falsepattern.zigbrains.project.ide.project.ZigProjectSettingsPanel;
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
import com.falsepattern.zigbrains.zig.lsp.ZLSStartupActivity;
import com.intellij.openapi.components.Service; import com.intellij.openapi.components.Service;
import com.intellij.openapi.components.State; import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage; import com.intellij.openapi.components.Storage;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import lombok.val; import lombok.val;
import org.jetbrains.annotations.Nullable;
import java.util.Objects; import java.util.Objects;
import java.util.function.Consumer;
@Service(Service.Level.PROJECT) @Service(Service.Level.PROJECT)
@State( @State(

View file

@ -21,11 +21,8 @@ import com.intellij.openapi.util.SystemInfo;
import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.lang.ref.WeakReference;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.WeakHashMap;
public class LocalZigToolchainProvider implements ZigToolchainProvider { public class LocalZigToolchainProvider implements ZigToolchainProvider {
private static final Map<Path, LocalZigToolchain> tcCache = ContainerUtil.createWeakKeyWeakValueMap(); private static final Map<Path, LocalZigToolchain> tcCache = ContainerUtil.createWeakKeyWeakValueMap();

View file

@ -16,15 +16,12 @@
package com.falsepattern.zigbrains.project.toolchain.stdlib; package com.falsepattern.zigbrains.project.toolchain.stdlib;
import com.falsepattern.zigbrains.common.util.ApplicationUtil;
import com.falsepattern.zigbrains.common.util.PathUtil; import com.falsepattern.zigbrains.common.util.PathUtil;
import com.falsepattern.zigbrains.project.openapi.components.ZigProjectSettingsService; import com.falsepattern.zigbrains.project.openapi.components.ZigProjectSettingsService;
import com.falsepattern.zigbrains.zig.Icons; import com.falsepattern.zigbrains.zig.Icons;
import com.falsepattern.zigbrains.zig.parser.ZigFile;
import com.intellij.navigation.ItemPresentation; import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectUtil;
import com.intellij.openapi.roots.SyntheticLibrary; import com.intellij.openapi.roots.SyntheticLibrary;
import com.intellij.openapi.util.NlsSafe; import com.intellij.openapi.util.NlsSafe;
import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VfsUtil;
@ -39,7 +36,6 @@ import javax.swing.Icon;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;

View file

@ -27,10 +27,7 @@ import org.jetbrains.annotations.Nullable;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
public class ZigCompilerTool extends AbstractZigTool{ public class ZigCompilerTool extends AbstractZigTool{
public static final String TOOL_NAME = "zig"; public static final String TOOL_NAME = "zig";

View file

@ -15,7 +15,6 @@
--> -->
<idea-plugin package="com.falsepattern.zigbrains.project"> <idea-plugin package="com.falsepattern.zigbrains.project">
<resource-bundle>zigbrains.project.Bundle</resource-bundle>
<extensions defaultExtensionNs="com.intellij"> <extensions defaultExtensionNs="com.intellij">
<configurationType implementation="com.falsepattern.zigbrains.project.execution.run.ConfigTypeRun"/> <configurationType implementation="com.falsepattern.zigbrains.project.execution.run.ConfigTypeRun"/>
<runConfigurationProducer implementation="com.falsepattern.zigbrains.project.execution.run.ConfigProducerRun"/> <runConfigurationProducer implementation="com.falsepattern.zigbrains.project.execution.run.ConfigProducerRun"/>
@ -35,7 +34,7 @@
<directoryProjectGenerator implementation="com.falsepattern.zigbrains.project.ide.newproject.ZigDirectoryProjectGenerator"/> <directoryProjectGenerator implementation="com.falsepattern.zigbrains.project.ide.newproject.ZigDirectoryProjectGenerator"/>
<newProjectWizard.languageGenerator implementation="com.falsepattern.zigbrains.project.ide.newproject.ZigNewProjectWizard"/> <newProjectWizard.languageGenerator implementation="com.falsepattern.zigbrains.project.ide.newproject.ZigNewProjectWizard"/>
<moduleBuilder builderClass="com.falsepattern.zigbrains.project.ide.util.projectwizard.ZigModuleBuilder"/> <moduleBuilder builderClass="com.falsepattern.zigbrains.project.ide.newproject.ZigModuleBuilder"/>
<projectConfigurable parentId="language" <projectConfigurable parentId="language"
instance="com.falsepattern.zigbrains.project.ide.config.ZigConfigurable" instance="com.falsepattern.zigbrains.project.ide.config.ZigConfigurable"
id="com.falsepattern.zigbrains.project.ide.config.ZigConfigurable" id="com.falsepattern.zigbrains.project.ide.config.ZigConfigurable"
@ -46,7 +45,7 @@
id="ZigDebugRunner"/> id="ZigDebugRunner"/>
<notificationGroup displayType="BALLOON" <notificationGroup displayType="BALLOON"
bundle="zigbrains.project.Bundle" bundle="zigbrains.Bundle"
key="notif-zig-project" key="notif-zig-project"
id="ZigBrains.Project"/> id="ZigBrains.Project"/>

View file

@ -1 +0,0 @@
notif-zig-project=Zig Project Status Notification

View file

@ -16,6 +16,7 @@
package com.falsepattern.zigbrains.zig.lsp; package com.falsepattern.zigbrains.zig.lsp;
import com.falsepattern.zigbrains.ZigBundle;
import com.falsepattern.zigbrains.common.util.ApplicationUtil; import com.falsepattern.zigbrains.common.util.ApplicationUtil;
import com.falsepattern.zigbrains.common.util.StringUtil; import com.falsepattern.zigbrains.common.util.StringUtil;
import com.falsepattern.zigbrains.lsp.IntellijLanguageClient; import com.falsepattern.zigbrains.lsp.IntellijLanguageClient;
@ -23,11 +24,18 @@ import com.falsepattern.zigbrains.lsp.utils.FileUtils;
import com.falsepattern.zigbrains.zig.environment.ZLSConfigProvider; import com.falsepattern.zigbrains.zig.environment.ZLSConfigProvider;
import com.falsepattern.zigbrains.zig.settings.ZLSProjectSettingsService; import com.falsepattern.zigbrains.zig.settings.ZLSProjectSettingsService;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.intellij.ide.BrowserUtil;
import com.intellij.ide.plugins.PluginManager;
import com.intellij.ide.plugins.PluginManagerConfigurable;
import com.intellij.notification.Notification; import com.intellij.notification.Notification;
import com.intellij.notification.NotificationAction;
import com.intellij.notification.NotificationType; import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications; import com.intellij.notification.Notifications;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.ProjectActivity; import com.intellij.openapi.startup.ProjectActivity;
import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.FileUtil;
@ -166,11 +174,42 @@ public class ZLSStartupActivity implements ProjectActivity {
return true; return true;
} }
private static boolean firstInit = true;
@Nullable @Nullable
@Override @Override
public Object execute(@NotNull Project project, @NotNull Continuation<? super Unit> continuation) { public Object execute(@NotNull Project project, @NotNull Continuation<? super Unit> continuation) {
val svc = ZLSProjectSettingsService.getInstance(project); val svc = ZLSProjectSettingsService.getInstance(project);
val state = svc.getState(); val state = svc.getState();
if (firstInit) {
firstInit = false;
if (!PluginManager.isPluginInstalled(PluginId.getId("com.intellij.modules.cidr.debugger")) && PluginManager.isPluginInstalled(PluginId.getId("com.intellij.modules.nativeDebug-plugin-capable"))) {
val notif = new Notification(
"ZigBrains",
ZigBundle.message("notification.nativedebug.title"),
ZigBundle.message("notification.nativedebug.text"),
NotificationType.INFORMATION
);
notif.addAction(new NotificationAction(ZigBundle.message("notification.nativedebug.market")) {
@Override
public void actionPerformed(@NotNull AnActionEvent e, @NotNull Notification notification) {
val configurable = new PluginManagerConfigurable();
ShowSettingsUtil.getInstance().editConfigurable((Project)null,
configurable,
() -> {
configurable.openMarketplaceTab("/vendor:\"JetBrains s.r.o.\" /tag:Debugging \"Native Debugging Support\"");
});
}
});
notif.addAction(new NotificationAction(ZigBundle.message("notification.nativedebug.browser")) {
@Override
public void actionPerformed(@NotNull AnActionEvent e, @NotNull Notification notification) {
BrowserUtil.browse("https://plugins.jetbrains.com/plugin/12775-native-debugging-support");
}
});
Notifications.Bus.notify(notif);
}
}
var zlsPath = state.zlsPath; var zlsPath = state.zlsPath;
if (zlsPath == null) { if (zlsPath == null) {

View file

@ -15,7 +15,6 @@
--> -->
<idea-plugin package="com.falsepattern.zigbrains.zig"> <idea-plugin package="com.falsepattern.zigbrains.zig">
<resource-bundle>zigbrains.zig.Bundle</resource-bundle>
<extensions defaultExtensionNs="com.intellij"> <extensions defaultExtensionNs="com.intellij">
<!-- region LSP --> <!-- region LSP -->
@ -68,7 +67,7 @@
<!-- needed for inlay hints --> <!-- needed for inlay hints -->
<codeInsight.declarativeInlayProvider implementationClass="com.falsepattern.zigbrains.lsp.contributors.LSPInlayHintProvider" <codeInsight.declarativeInlayProvider implementationClass="com.falsepattern.zigbrains.lsp.contributors.LSPInlayHintProvider"
bundle="zigbrains.zig.Bundle" bundle="zigbrains.Bundle"
nameKey="inlayprovider" nameKey="inlayprovider"
providerId="ZigBrains" providerId="ZigBrains"
isEnabledByDefault="true" isEnabledByDefault="true"
@ -100,8 +99,8 @@
<postStartupActivity implementation="com.falsepattern.zigbrains.zig.lsp.ZLSStartupActivity"/> <postStartupActivity implementation="com.falsepattern.zigbrains.zig.lsp.ZLSStartupActivity"/>
<notificationGroup displayType="BALLOON" <notificationGroup displayType="BALLOON"
bundle="zigbrains.zig.Bundle" bundle="zigbrains.Bundle"
key="notif-zls" key="notif-zls-error"
id="ZigBrains.ZLS"/> id="ZigBrains.ZLS"/>
<codeInsight.parameterInfo language="Zig" <codeInsight.parameterInfo language="Zig"

View file

@ -1,2 +0,0 @@
inlayprovider=ZLS Inlay Provider
notif-zls=ZLS Error Notification

View file

@ -34,7 +34,11 @@ These art assets are licensed under Creative Commons Attribution-ShareAlike 4.0
Parts of the codebase are based on the intellij-zig plugin, Parts of the codebase are based on the intellij-zig plugin,
developed by HTGAzureX1212 (https://github.com/HTGAzureX1212), licensed under the Apache 2.0 license. developed by HTGAzureX1212 (https://github.com/HTGAzureX1212), licensed under the Apache 2.0 license.
-------------------------------- --------------------------------
Parts of the codebase are based on the intellij-rust plugin,
developed by the intellij-rust team (https://github.com/intellij-rust), licensed under the intellij-rust MIT license.
--------------------------------
All of the licenses listed here are available in the following files, bundled with the plugin: All of the licenses listed here are available in the following files, bundled with the plugin:
- licenses/APACHE_2.0.LICENSE - licenses/APACHE_2.0.LICENSE
- licenses/CC_BY_SA_4.0.LICENSE - licenses/CC_BY_SA_4.0.LICENSE
- licenses/INTELLIJ-RUST.LICENSE

View file

@ -1,5 +1,6 @@
<!-- Plugin Configuration File. Read more: https://plugins.jetbrains.com/docs/intellij/plugin-configuration-file.html --> <!-- Plugin Configuration File. Read more: https://plugins.jetbrains.com/docs/intellij/plugin-configuration-file.html -->
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude" require-restart="true"> <idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude" require-restart="true">
<resource-bundle>zigbrains.Bundle</resource-bundle>
<id>com.falsepattern.zigbrains</id> <id>com.falsepattern.zigbrains</id>
<name>ZigBrains</name> <name>ZigBrains</name>
<vendor>FalsePattern</vendor> <vendor>FalsePattern</vendor>
@ -10,8 +11,14 @@
<xi:include href="/META-INF/zigbrains-zon.xml"/> <xi:include href="/META-INF/zigbrains-zon.xml"/>
<xi:include href="/META-INF/zigbrains-project.xml"/> <xi:include href="/META-INF/zigbrains-project.xml"/>
<depends optional="true" config-file="zigbrains-zig-debugger.xml">com.intellij.modules.cidr.debugger</depends> <depends optional="true" config-file="zigbrains-zig-debugger.xml">com.intellij.modules.cidr.debugger</depends>
<depends optional="true" config-file="zigbrains-zig-cpp.xml">com.intellij.modules.clion</depends> <depends optional="true" config-file="zigbrains-zig-clion.xml">com.intellij.modules.clion</depends>
<extensions defaultExtensionNs="com.intellij">
<notificationGroup displayType="BALLOON"
bundle="zigbrains.Bundle"
key="notif-zb"
id="ZigBrains"/>
</extensions>
<extensionPoints> <extensionPoints>
<extensionPoint <extensionPoint
interface="com.falsepattern.zigbrains.project.toolchain.flavours.AbstractZigToolchainFlavour" dynamic="true" interface="com.falsepattern.zigbrains.project.toolchain.flavours.AbstractZigToolchainFlavour" dynamic="true"
@ -23,7 +30,7 @@
interface="com.falsepattern.zigbrains.zig.environment.ZLSConfigProvider" dynamic="true" interface="com.falsepattern.zigbrains.zig.environment.ZLSConfigProvider" dynamic="true"
name="zlsConfigProvider"/> name="zlsConfigProvider"/>
<extensionPoint <extensionPoint
interface="com.falsepattern.zigbrains.debugbridge.DebuggerDriverProvider" dynamic="true" interface="com.falsepattern.zigbrains.debugbridge.ZigDebuggerDriverConfigurationProvider" dynamic="true"
name="debuggerDriverProvider"/> name="debuggerDriverProvider"/>
<extensionPoint <extensionPoint
interface="com.falsepattern.zigbrains.common.ZBFeatures" dynamic="true" interface="com.falsepattern.zigbrains.common.ZBFeatures" dynamic="true"

View file

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Aleksey Kladov, Evgeny Kurbatsky, Alexey Kudinkin and contributors
Copyright (c) 2016 JetBrains
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.