backport: 14.0.0
This commit is contained in:
parent
0bbb5095a9
commit
938ac8add7
68 changed files with 1882 additions and 1277 deletions
32
CHANGELOG.md
32
CHANGELOG.md
|
@ -18,6 +18,38 @@ Changelog structure reference:
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [14.0.0]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- LSP
|
||||||
|
- The status widget now auto-hides itself when the selected editor is not a zig file in the current window
|
||||||
|
|
||||||
|
- Project
|
||||||
|
- Completely overhauled the configuration system and the new project creation window. All the configs have been unified
|
||||||
|
into a single screen, and project creation has been fully integrated as a mainline feature, instead of just a "nice to have".
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- LSP
|
||||||
|
- The injection of the various language actions (Go to declaration/implementation, reformat, etc.) has been
|
||||||
|
reimplemented from the ground up to be much more reliable and compatible in the presence of other languages and plugins.
|
||||||
|
|
||||||
|
- Zig, ZLS
|
||||||
|
- The configurations have been unified into a single cohesive interface
|
||||||
|
- Improved auto-detection for both Zig and ZLS
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- LSP
|
||||||
|
- Putting the caret on a diagnostics error now no longer highlights the whole file
|
||||||
|
|
||||||
|
- Project
|
||||||
|
- Fixed invalid --colored command line argument for zig tasks
|
||||||
|
|
||||||
|
- Zig
|
||||||
|
- More robust indentation logic, also works with semi-invalid syntax now
|
||||||
|
|
||||||
## [13.2.0]
|
## [13.2.0]
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
69
README.md
69
README.md
|
@ -1,5 +1,9 @@
|
||||||
# ZigBrains
|
# ZigBrains
|
||||||
|
|
||||||
|
### [Website](https://falsepattern.com/zigbrains)
|
||||||
|
|
||||||
|
### [JetBrains Marketplace](https://plugins.jetbrains.com/plugin/22456-zigbrains)
|
||||||
|
|
||||||
## Developer guide
|
## Developer guide
|
||||||
|
|
||||||
### All platforms
|
### All platforms
|
||||||
|
@ -50,24 +54,15 @@ and might as well utilize the full semver string for extra information.
|
||||||
# Description
|
# Description
|
||||||
|
|
||||||
<!-- Plugin description -->
|
<!-- Plugin description -->
|
||||||
A multifunctional Zig Programming Language plugin for the IDEA platform.
|
Adds support for the Zig Language, utilizing the ZLS language server for advanced coding assistance.
|
||||||
|
|
||||||
Core features:
|
## Quick setup guide for Zig and ZLS
|
||||||
- Uses ZLS (Zig Language Server) for code assistance, syntax highlighting, and anything to do with coding assistance
|
|
||||||
- Supports build.zig.zon files with autocomplete
|
|
||||||
- Per-project Zig toolchain integration
|
|
||||||
- Debugging support for CLion (builtin), and IDEA Ultimate [With this plugin](https://plugins.jetbrains.com/plugin/12775-native-debugging-support)
|
|
||||||
- Gutter icon for running main(), tests, and build
|
|
||||||
|
|
||||||
|
1. Download the latest version of Zig from https://ziglang.org/download
|
||||||
## Setting up the language server
|
2. Download and compile the ZLS language server, available at https://github.com/zigtools/zls
|
||||||
|
3. Go to `Settings` -> `Languages & Frameworks` -> `Zig`, and point the `Toolchain Location` and `ZLS path` to the correct places
|
||||||
If you have `zls` available on PATH, ZigBrains will automatically discover it. If not, follow this guide:
|
4. Open a .zig file, and wait for the circle in the bottom status bar to turn Green (empty).
|
||||||
|
See below (`LSP status icon explanation`) for an explanation on what the circle means.
|
||||||
1. Download or compile the ZLS language server, available at https://github.com/zigtools/zls
|
|
||||||
2. Go to `Settings` -> `Languages & Frameworks` -> `ZLS` -> `ZLS path` -> set the path to the `zls` executable you downloaded or compiled
|
|
||||||
3. Open a .zig file, and wait for the circle in the bottom status bar to turn Green (empty).
|
|
||||||
See below for an explanation on what the circle means.
|
|
||||||
|
|
||||||
### LSP status icon explanation
|
### LSP status icon explanation
|
||||||
Red (X symbol):
|
Red (X symbol):
|
||||||
|
@ -81,6 +76,13 @@ LSP server is running.
|
||||||
|
|
||||||
## Debugging
|
## Debugging
|
||||||
|
|
||||||
|
### Note
|
||||||
|
Debugging on Linux/MacOS/Unix is only available in CLion, as ZigBrains depends on the C++ toolchains system.
|
||||||
|
|
||||||
|
On Windows, debugging is also available with the help of the
|
||||||
|
[Native Debugging Support](https://plugins.jetbrains.com/plugin/12775-native-debugging-support), which is unfortunately
|
||||||
|
only compatible with paid IDEs.
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
Due to technical limitations, the C++ toolchains cannot be used for debugging zig code on windows.
|
Due to technical limitations, the C++ toolchains cannot be used for debugging zig code on windows.
|
||||||
|
@ -102,39 +104,4 @@ Note: There is a small issue with the LLDB debugger which does not happen with G
|
||||||
instruction (usually, deep inside the zig standard library's startup code). Unfortunately, we have not found a fix for
|
instruction (usually, deep inside the zig standard library's startup code). Unfortunately, we have not found a fix for
|
||||||
this yet, but fortunately it doesn't break anything, just a bit of inconvenience.
|
this yet, but fortunately it doesn't break anything, just a bit of inconvenience.
|
||||||
|
|
||||||
## Feature tracker:
|
|
||||||
|
|
||||||
### .zig files:
|
|
||||||
- Code completion
|
|
||||||
- Code folding
|
|
||||||
- Code formatting
|
|
||||||
- Syntax highlighting
|
|
||||||
- Inlay hints
|
|
||||||
- Basic error diagnostics
|
|
||||||
- Go to definition
|
|
||||||
- Rename symbol
|
|
||||||
- Hover documentation
|
|
||||||
- Go to implementations / find usages
|
|
||||||
- Brace/Parenthesis/Bracket matching
|
|
||||||
- Debugging (CLion/CLion Nova)
|
|
||||||
- File creation prompt
|
|
||||||
- Gutter launch buttons
|
|
||||||
- Commenter (thanks @MarioAriasC !)
|
|
||||||
|
|
||||||
- TODO:
|
|
||||||
- Workspace Symbols
|
|
||||||
|
|
||||||
### .zon files:
|
|
||||||
- Syntax highlighting
|
|
||||||
- Formatting and indentation
|
|
||||||
- Code completion
|
|
||||||
- Brace folding
|
|
||||||
- Automatic brace and quote pairing
|
|
||||||
|
|
||||||
### Toolchain:
|
|
||||||
- Basic per-project toolchain management
|
|
||||||
- Run configurations
|
|
||||||
- Debugging (CLion/IDEA Ultimate)
|
|
||||||
- Project generation (thanks @JensvandeWiel !)
|
|
||||||
|
|
||||||
<!-- Plugin description end -->
|
<!-- Plugin description end -->
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* 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.common;
|
||||||
|
|
||||||
|
import com.intellij.openapi.options.Configurable;
|
||||||
|
import com.intellij.openapi.options.ConfigurationException;
|
||||||
|
import com.intellij.ui.JBColor;
|
||||||
|
import lombok.val;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static com.falsepattern.zigbrains.common.util.dsl.JavaPanel.newPanel;
|
||||||
|
|
||||||
|
public abstract class MultiConfigurable implements Configurable {
|
||||||
|
private final SubConfigurable[] configurables;
|
||||||
|
protected MultiConfigurable(SubConfigurable... configurables) {
|
||||||
|
this.configurables = Arrays.copyOf(configurables, configurables.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable JComponent createComponent() {
|
||||||
|
return newPanel(p -> {
|
||||||
|
for (val configurable: configurables) {
|
||||||
|
configurable.createComponent(p);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isModified() {
|
||||||
|
for (val configurable: configurables) {
|
||||||
|
if (configurable.isModified())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply() throws ConfigurationException {
|
||||||
|
for (val config: configurables) {
|
||||||
|
config.apply();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
for (val config: configurables) {
|
||||||
|
config.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disposeUIResources() {
|
||||||
|
for (val config: configurables) {
|
||||||
|
config.disposeUIResources();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* 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.common;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.common.util.dsl.JavaPanel;
|
||||||
|
import com.intellij.openapi.options.ConfigurationException;
|
||||||
|
|
||||||
|
public interface SubConfigurable {
|
||||||
|
void createComponent(JavaPanel panel);
|
||||||
|
boolean isModified();
|
||||||
|
void apply() throws ConfigurationException;
|
||||||
|
void reset();
|
||||||
|
void disposeUIResources();
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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.common;
|
||||||
|
|
||||||
|
import com.intellij.openapi.components.PersistentStateComponent;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public abstract class WrappingStateComponent<T> implements PersistentStateComponent<T> {
|
||||||
|
private T state;
|
||||||
|
public WrappingStateComponent(@NotNull T initialState) {
|
||||||
|
this.state = initialState;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull T getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadState(@NotNull T state) {
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@
|
||||||
package com.falsepattern.zigbrains.common.util;
|
package com.falsepattern.zigbrains.common.util;
|
||||||
|
|
||||||
import com.intellij.openapi.diagnostic.Logger;
|
import com.intellij.openapi.diagnostic.Logger;
|
||||||
|
import com.intellij.openapi.util.SystemInfo;
|
||||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
@ -24,7 +25,9 @@ import org.jetbrains.annotations.Nullable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public class FileUtil {
|
public class FileUtil {
|
||||||
private static final Logger LOG = Logger.getInstance(FileUtil.class);
|
private static final Logger LOG = Logger.getInstance(FileUtil.class);
|
||||||
|
@ -96,6 +99,10 @@ public class FileUtil {
|
||||||
return LocalFileSystem.getInstance().findFileByIoFile(new File(uri));
|
return LocalFileSystem.getInstance().findFileByIoFile(new File(uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static VirtualFile virtualFileFromPath(Path path) {
|
||||||
|
return LocalFileSystem.getInstance().findFileByNioFile(path);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms an URI string into a VFS file
|
* Transforms an URI string into a VFS file
|
||||||
*
|
*
|
||||||
|
@ -125,6 +132,28 @@ public class FileUtil {
|
||||||
return path != null ? sanitizeURI(path.toUri().toString()) : null;
|
return path != null ? sanitizeURI(path.toUri().toString()) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Optional<Path> findExecutableOnPATH(String exe) {
|
||||||
|
var exeName = SystemInfo.isWindows ? exe + ".exe" : exe;
|
||||||
|
var PATH = System.getenv("PATH").split(File.pathSeparator);
|
||||||
|
for (var dir: PATH) {
|
||||||
|
var path = Path.of(dir);
|
||||||
|
try {
|
||||||
|
path = path.toAbsolutePath();
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!Files.exists(path) || !Files.isDirectory(path)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var exePath = path.resolve(exeName).toAbsolutePath();
|
||||||
|
if (!Files.isRegularFile(exePath) || !Files.isExecutable(exePath)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return Optional.of(exePath);
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object representing the OS type (Windows or Unix)
|
* Object representing the OS type (Windows or Unix)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* 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.common.util;
|
||||||
|
|
||||||
|
import kotlin.Unit;
|
||||||
|
import kotlin.jvm.functions.Function1;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class KtUtil {
|
||||||
|
public static <T> Function1<T, Unit> $f(Consumer<T> f) {
|
||||||
|
return (x) -> {
|
||||||
|
f.accept(x);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,8 +17,11 @@
|
||||||
package com.falsepattern.zigbrains.common.util;
|
package com.falsepattern.zigbrains.common.util;
|
||||||
|
|
||||||
import com.intellij.openapi.util.SystemInfo;
|
import com.intellij.openapi.util.SystemInfo;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.InvalidPathException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
public class PathUtil {
|
public class PathUtil {
|
||||||
|
@ -30,4 +33,22 @@ public class PathUtil {
|
||||||
var exeName = SystemInfo.isWindows ? toolName + ".exe" : toolName;
|
var exeName = SystemInfo.isWindows ? toolName + ".exe" : toolName;
|
||||||
return path.resolve(exeName).toAbsolutePath();
|
return path.resolve(exeName).toAbsolutePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static @Nullable Path pathFromString(@Nullable String pathString) {
|
||||||
|
if (pathString == null || pathString.isBlank()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Path.of(pathString);
|
||||||
|
} catch (InvalidPathException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NotNull String stringFromPath(@Nullable Path path) {
|
||||||
|
if (path == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return path.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import com.intellij.openapi.ui.TextComponentAccessor;
|
||||||
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
||||||
import com.intellij.openapi.util.NlsContexts;
|
import com.intellij.openapi.util.NlsContexts;
|
||||||
import com.intellij.ui.DocumentAdapter;
|
import com.intellij.ui.DocumentAdapter;
|
||||||
|
import com.intellij.ui.components.fields.ExtendableTextField;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
@ -53,7 +54,7 @@ public class TextFieldUtil {
|
||||||
Disposable disposable,
|
Disposable disposable,
|
||||||
@NlsContexts.DialogTitle String dialogTitle,
|
@NlsContexts.DialogTitle String dialogTitle,
|
||||||
Runnable onTextChanged) {
|
Runnable onTextChanged) {
|
||||||
val component = new TextFieldWithBrowseButton(null, disposable);
|
val component = new TextFieldWithBrowseButton(new ExtendableTextField(), null, disposable);
|
||||||
component.addBrowseFolderListener(dialogTitle, null, null, fileChooserDescriptor, TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT);
|
component.addBrowseFolderListener(dialogTitle, null, null, fileChooserDescriptor, TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT);
|
||||||
addTextChangeListener(component.getChildComponent(), ignored -> onTextChanged.run());
|
addTextChangeListener(component.getChildComponent(), ignored -> onTextChanged.run());
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* 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.common.util.dsl;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.common.util.KtUtil;
|
||||||
|
import com.intellij.openapi.ui.DialogPanel;
|
||||||
|
import com.intellij.ui.components.JBLabel;
|
||||||
|
import com.intellij.ui.dsl.builder.Align;
|
||||||
|
import com.intellij.ui.dsl.builder.AlignX;
|
||||||
|
import com.intellij.ui.dsl.builder.BuilderKt;
|
||||||
|
import com.intellij.ui.dsl.builder.Panel;
|
||||||
|
import com.intellij.ui.dsl.builder.RightGap;
|
||||||
|
import com.intellij.ui.dsl.builder.Row;
|
||||||
|
import com.intellij.ui.dsl.builder.RowsRange;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import static com.falsepattern.zigbrains.common.util.KtUtil.$f;
|
||||||
|
|
||||||
|
public class JavaPanel {
|
||||||
|
private final Panel panel;
|
||||||
|
|
||||||
|
public JavaPanel(Panel p) {
|
||||||
|
this.panel = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cell(String label, JComponent component, Align align) {
|
||||||
|
row(label, row -> row.cell(component).align(align));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cell(String label, JComponent component) {
|
||||||
|
row(label, row -> row.cell(component));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cell(JComponent component) {
|
||||||
|
cell("", component);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void label(String label) {
|
||||||
|
panel.row((JLabel) null, $f(r -> r.label(label)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void gap() {
|
||||||
|
panel.gap(RightGap.SMALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void row(Consumer<Row> row) {
|
||||||
|
panel.row((JLabel) null, (r) -> {
|
||||||
|
row.accept(r);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void row(String text, Consumer<Row> row) {
|
||||||
|
panel.row(text, $f(row));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void separator() {
|
||||||
|
panel.separator(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void separator(Color color) {
|
||||||
|
panel.separator(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void panel(Consumer<JavaPanel> c) {
|
||||||
|
panel.panel($f(p -> {
|
||||||
|
c.accept(new JavaPanel(p));
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DialogPanel newPanel(Consumer<JavaPanel> c) {
|
||||||
|
return BuilderKt.panel((p) -> {
|
||||||
|
c.accept(new JavaPanel(p));
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void group(String title, boolean open, Consumer<JavaPanel> c) {
|
||||||
|
panel.collapsibleGroup(title, true, p -> {
|
||||||
|
c.accept(new JavaPanel(p));
|
||||||
|
return null;
|
||||||
|
}).setExpanded(open);
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,8 +40,8 @@ public class ZigExecConfigBinary extends ZigExecConfigBase<ZigExecConfigBinary>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] buildCommandLineArgs() {
|
public List<String> buildCommandLineArgs(boolean debug) {
|
||||||
return args.args;
|
return List.of(args.args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -36,7 +36,6 @@ import org.eclipse.lsp4j.DidChangeConfigurationParams;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* 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.lsp.actions;
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.actions.ReformatCodeAction;
|
||||||
|
import com.intellij.codeInsight.actions.ShowReformatFileDialog;
|
||||||
|
import com.intellij.codeInsight.hint.actions.ShowImplementationsAction;
|
||||||
|
import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction;
|
||||||
|
import com.intellij.codeInsight.navigation.actions.GotoImplementationAction;
|
||||||
|
import com.intellij.openapi.actionSystem.ActionManager;
|
||||||
|
import com.intellij.openapi.actionSystem.AnAction;
|
||||||
|
import com.intellij.openapi.actionSystem.impl.DynamicActionConfigurationCustomizer;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.val;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class ActionCustomizer implements DynamicActionConfigurationCustomizer {
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
private static class ActionWrapper<T extends AnAction> {
|
||||||
|
public final Class<T> klass;
|
||||||
|
public final Function<T, WrappedAction<T>> wrapper;
|
||||||
|
}
|
||||||
|
private static final Map<String, ActionWrapper<?>> actions = new HashMap<>();
|
||||||
|
static {
|
||||||
|
actions.put("GotoDeclaration", new ActionWrapper<>(GotoDeclarationAction.class, LSPGotoDeclarationAction::new));
|
||||||
|
actions.put("GotoImplementation", new ActionWrapper<>(GotoImplementationAction.class, LSPGotoImplementationAction::new));
|
||||||
|
actions.put("ReformatCode", new ActionWrapper<>(ReformatCodeAction.class, LSPReformatAction::new));
|
||||||
|
actions.put("QuickImplementations", new ActionWrapper<>(ShowImplementationsAction.class, LSPShowImplementationsAction::new));
|
||||||
|
actions.put("ShowReformatFileDialog", new ActionWrapper<>(ShowReformatFileDialog.class, LSPShowReformatDialogAction::new));
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void registerActions(@NotNull ActionManager manager) {
|
||||||
|
for (val entry: actions.entrySet()) {
|
||||||
|
wrap(manager, entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unregisterActions(@NotNull ActionManager manager) {
|
||||||
|
for (val name: actions.keySet()) {
|
||||||
|
unwrap(manager, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends AnAction> void wrap(ActionManager manager, String name, ActionWrapper<T> constructor) {
|
||||||
|
val oldAction = manager.getAction(name);
|
||||||
|
|
||||||
|
if (constructor.klass.isInstance(oldAction)) {
|
||||||
|
val wrapped = constructor.wrapper.apply(constructor.klass.cast(oldAction));
|
||||||
|
wrapped.copyFrom(oldAction);
|
||||||
|
manager.replaceAction(name, wrapped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void unwrap(ActionManager manager, String name) {
|
||||||
|
val oldAction = manager.getAction(name);
|
||||||
|
if (oldAction instanceof WrappedAction<?> w) {
|
||||||
|
manager.replaceAction(name, w.wrapped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,42 +16,28 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.lsp.actions;
|
package com.falsepattern.zigbrains.lsp.actions;
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.lsp.IntellijLanguageClient;
|
|
||||||
import com.falsepattern.zigbrains.lsp.editor.EditorEventManager;
|
import com.falsepattern.zigbrains.lsp.editor.EditorEventManager;
|
||||||
import com.falsepattern.zigbrains.lsp.editor.EditorEventManagerBase;
|
import com.intellij.codeInsight.navigation.CtrlMouseAction;
|
||||||
|
import com.intellij.codeInsight.navigation.CtrlMouseData;
|
||||||
import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction;
|
import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction;
|
||||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
|
||||||
import com.intellij.openapi.editor.Editor;
|
import com.intellij.openapi.editor.Editor;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.DumbAware;
|
||||||
import com.intellij.psi.PsiDocumentManager;
|
|
||||||
import com.intellij.psi.PsiFile;
|
import com.intellij.psi.PsiFile;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public class LSPGotoDeclarationAction extends WrappedAction<GotoDeclarationAction> implements DumbAware {
|
||||||
|
public LSPGotoDeclarationAction(GotoDeclarationAction wrapped) {
|
||||||
|
super(wrapped);
|
||||||
|
}
|
||||||
|
|
||||||
public class LSPGotoDeclarationAction extends GotoDeclarationAction {
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
public void actionPerformedLSP(@NotNull AnActionEvent e, EditorEventManager manager, PsiFile file) {
|
||||||
Project project = e.getData(CommonDataKeys.PROJECT);
|
val offset = manager.editor.getCaretModel().getOffset();
|
||||||
Editor editor = e.getData(CommonDataKeys.EDITOR);
|
|
||||||
if (editor == null || project == null) {
|
|
||||||
super.actionPerformed(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
|
|
||||||
if (file == null || !IntellijLanguageClient.isExtensionSupported(file.getVirtualFile())) {
|
|
||||||
super.actionPerformed(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
EditorEventManager manager = EditorEventManagerBase.forEditor(editor);
|
|
||||||
if (manager == null) {
|
|
||||||
super.actionPerformed(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
val offset = editor.getCaretModel().getOffset();
|
|
||||||
val psiElement = file.findElementAt(offset);
|
val psiElement = file.findElementAt(offset);
|
||||||
if (psiElement == null) {
|
if (psiElement == null) {
|
||||||
super.actionPerformed(e);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
manager.gotoDeclarationOrUsages(psiElement);
|
manager.gotoDeclarationOrUsages(psiElement);
|
||||||
|
|
|
@ -1,61 +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.lsp.actions;
|
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.lsp.IntellijLanguageClient;
|
|
||||||
import com.falsepattern.zigbrains.lsp.editor.EditorEventManager;
|
|
||||||
import com.falsepattern.zigbrains.lsp.editor.EditorEventManagerBase;
|
|
||||||
import com.intellij.codeInsight.hint.actions.ShowImplementationsAction;
|
|
||||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
|
||||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
|
||||||
import com.intellij.openapi.editor.Editor;
|
|
||||||
import com.intellij.openapi.project.Project;
|
|
||||||
import com.intellij.psi.PsiDocumentManager;
|
|
||||||
import com.intellij.psi.PsiFile;
|
|
||||||
import lombok.val;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
public class LSPGotoDefinitionAction extends ShowImplementationsAction {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
|
||||||
Project project = e.getData(CommonDataKeys.PROJECT);
|
|
||||||
Editor editor = e.getData(CommonDataKeys.EDITOR);
|
|
||||||
if (editor == null || project == null) {
|
|
||||||
super.actionPerformed(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
|
|
||||||
if (file == null || !IntellijLanguageClient.isExtensionSupported(file.getVirtualFile())) {
|
|
||||||
super.actionPerformed(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
EditorEventManager manager = EditorEventManagerBase.forEditor(editor);
|
|
||||||
if (manager == null) {
|
|
||||||
super.actionPerformed(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
val offset = editor.getCaretModel().getOffset();
|
|
||||||
val psiElement = file.findElementAt(offset);
|
|
||||||
if (psiElement == null) {
|
|
||||||
super.actionPerformed(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!manager.gotoDefinition(psiElement)) {
|
|
||||||
super.actionPerformed(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* 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.lsp.actions;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.lsp.editor.EditorEventManager;
|
||||||
|
import com.intellij.codeInsight.navigation.CtrlMouseAction;
|
||||||
|
import com.intellij.codeInsight.navigation.CtrlMouseData;
|
||||||
|
import com.intellij.codeInsight.navigation.CtrlMouseInfo;
|
||||||
|
import com.intellij.codeInsight.navigation.actions.GotoImplementationAction;
|
||||||
|
import com.intellij.idea.ActionsBundle;
|
||||||
|
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||||
|
import com.intellij.openapi.actionSystem.PerformWithDocumentsCommitted;
|
||||||
|
import com.intellij.openapi.editor.Editor;
|
||||||
|
import com.intellij.psi.PsiFile;
|
||||||
|
import lombok.val;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public class LSPGotoImplementationAction extends WrappedAction<GotoImplementationAction> implements PerformWithDocumentsCommitted {
|
||||||
|
public LSPGotoImplementationAction(GotoImplementationAction wrapped) {
|
||||||
|
super(wrapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void actionPerformedLSP(AnActionEvent e, EditorEventManager manager, PsiFile file) {
|
||||||
|
val offset = manager.editor.getCaretModel().getOffset();
|
||||||
|
val psiElement = file.findElementAt(offset);
|
||||||
|
if (psiElement == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
manager.gotoDefinition(psiElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateLSP(AnActionEvent e, EditorEventManager manager, PsiFile file) {
|
||||||
|
if (e.getPresentation().getTextWithMnemonic() == null) {
|
||||||
|
e.getPresentation().setText(ActionsBundle.actionText("GotoImplementation"));
|
||||||
|
e.getPresentation().setDescription(ActionsBundle.actionDescription("GotoImplementation"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,39 +16,28 @@
|
||||||
package com.falsepattern.zigbrains.lsp.actions;
|
package com.falsepattern.zigbrains.lsp.actions;
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.common.util.ApplicationUtil;
|
import com.falsepattern.zigbrains.common.util.ApplicationUtil;
|
||||||
import com.falsepattern.zigbrains.lsp.IntellijLanguageClient;
|
import com.falsepattern.zigbrains.lsp.editor.EditorEventManager;
|
||||||
import com.falsepattern.zigbrains.lsp.requests.ReformatHandler;
|
import com.falsepattern.zigbrains.lsp.requests.ReformatHandler;
|
||||||
import com.intellij.codeInsight.actions.ReformatCodeAction;
|
import com.intellij.codeInsight.actions.ReformatCodeAction;
|
||||||
|
import com.intellij.ide.lightEdit.LightEditCompatible;
|
||||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
|
||||||
import com.intellij.openapi.diagnostic.Logger;
|
|
||||||
import com.intellij.openapi.editor.Editor;
|
|
||||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||||
import com.intellij.openapi.project.DumbAware;
|
import com.intellij.openapi.project.DumbAware;
|
||||||
import com.intellij.openapi.project.Project;
|
|
||||||
import com.intellij.psi.PsiDocumentManager;
|
|
||||||
import com.intellij.psi.PsiFile;
|
import com.intellij.psi.PsiFile;
|
||||||
|
import lombok.val;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action overriding the default reformat action
|
* Action overriding the default reformat action
|
||||||
* Fallback to the default action if the language is already supported or not supported by any language server
|
* Fallback to the default action if the language is already supported or not supported by any language server
|
||||||
*/
|
*/
|
||||||
public class LSPReformatAction extends ReformatCodeAction implements DumbAware {
|
public class LSPReformatAction extends WrappedAction<ReformatCodeAction> implements DumbAware, LightEditCompatible {
|
||||||
private Logger LOG = Logger.getInstance(LSPReformatAction.class);
|
public LSPReformatAction(ReformatCodeAction wrapped) {
|
||||||
|
super(wrapped);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(AnActionEvent e) {
|
public void actionPerformedLSP(AnActionEvent e, EditorEventManager manager, PsiFile file) {
|
||||||
Project project = e.getData(CommonDataKeys.PROJECT);
|
val editor = manager.editor;
|
||||||
Editor editor = e.getData(CommonDataKeys.EDITOR);
|
|
||||||
if (editor == null || project == null) {
|
|
||||||
super.actionPerformed(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
|
|
||||||
if (file == null || !IntellijLanguageClient.isExtensionSupported(file.getVirtualFile())) {
|
|
||||||
super.actionPerformed(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ApplicationUtil.writeAction(() -> FileDocumentManager.getInstance().saveDocument(editor.getDocument()));
|
ApplicationUtil.writeAction(() -> FileDocumentManager.getInstance().saveDocument(editor.getDocument()));
|
||||||
// if editor hasSelection, only reformat selection, not reformat the whole file
|
// if editor hasSelection, only reformat selection, not reformat the whole file
|
||||||
if (editor.getSelectionModel().hasSelection()) {
|
if (editor.getSelectionModel().hasSelection()) {
|
||||||
|
@ -57,9 +46,4 @@ public class LSPReformatAction extends ReformatCodeAction implements DumbAware {
|
||||||
ReformatHandler.reformatFile(editor);
|
ReformatHandler.reformatFile(editor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update(AnActionEvent event) {
|
|
||||||
super.update(event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* 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.lsp.actions;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.lsp.editor.EditorEventManager;
|
||||||
|
import com.intellij.codeInsight.hint.actions.ShowImplementationsAction;
|
||||||
|
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||||
|
import com.intellij.openapi.project.DumbAware;
|
||||||
|
import com.intellij.psi.PsiFile;
|
||||||
|
import lombok.val;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class LSPShowImplementationsAction extends WrappedAction<ShowImplementationsAction> implements DumbAware {
|
||||||
|
public LSPShowImplementationsAction(ShowImplementationsAction wrapped) {
|
||||||
|
super(wrapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformedLSP(@NotNull AnActionEvent e, EditorEventManager manager, PsiFile file) {
|
||||||
|
val offset = manager.editor.getCaretModel().getOffset();
|
||||||
|
val psiElement = file.findElementAt(offset);
|
||||||
|
if (psiElement == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
manager.gotoDefinition(psiElement);
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,41 +23,33 @@ import com.intellij.codeInsight.actions.LayoutCodeOptions;
|
||||||
import com.intellij.codeInsight.actions.ShowReformatFileDialog;
|
import com.intellij.codeInsight.actions.ShowReformatFileDialog;
|
||||||
import com.intellij.codeInsight.actions.TextRangeType;
|
import com.intellij.codeInsight.actions.TextRangeType;
|
||||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
|
||||||
import com.intellij.openapi.diagnostic.Logger;
|
import com.intellij.openapi.diagnostic.Logger;
|
||||||
import com.intellij.openapi.editor.Editor;
|
|
||||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||||
import com.intellij.openapi.project.DumbAware;
|
import com.intellij.openapi.project.DumbAware;
|
||||||
import com.intellij.openapi.project.Project;
|
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
import com.intellij.psi.PsiDocumentManager;
|
|
||||||
import com.intellij.psi.PsiFile;
|
import com.intellij.psi.PsiFile;
|
||||||
|
import lombok.val;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class overriding the default action handling the Reformat dialog event (CTRL+ALT+SHIFT+L by default)
|
* Class overriding the default action handling the Reformat dialog event (CTRL+ALT+SHIFT+L by default)
|
||||||
* Fallback to the default action if the language is already supported or not supported by any language server
|
* Fallback to the default action if the language is already supported or not supported by any language server
|
||||||
*/
|
*/
|
||||||
public class LSPShowReformatDialogAction extends ShowReformatFileDialog implements DumbAware {
|
public class LSPShowReformatDialogAction extends WrappedAction<ShowReformatFileDialog> implements DumbAware {
|
||||||
|
|
||||||
private String HELP_ID = "editing.codeReformatting";
|
private String HELP_ID = "editing.codeReformatting";
|
||||||
private Logger LOG = Logger.getInstance(LSPShowReformatDialogAction.class);
|
private Logger LOG = Logger.getInstance(LSPShowReformatDialogAction.class);
|
||||||
|
|
||||||
@Override
|
public LSPShowReformatDialogAction(ShowReformatFileDialog wrapped) {
|
||||||
public void actionPerformed(AnActionEvent e) {
|
super(wrapped);
|
||||||
Editor editor = e.getData(CommonDataKeys.EDITOR);
|
}
|
||||||
Project project = e.getData(CommonDataKeys.PROJECT);
|
|
||||||
|
|
||||||
if (editor == null || project == null) {
|
@Override
|
||||||
super.actionPerformed(e);
|
public void actionPerformedLSP(AnActionEvent e, EditorEventManager manager, PsiFile psiFile) {
|
||||||
return;
|
val editor = manager.editor;
|
||||||
}
|
val project = manager.getProject();
|
||||||
PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
|
|
||||||
if (psiFile == null) {
|
|
||||||
super.actionPerformed(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
VirtualFile virFile = FileDocumentManager.getInstance().getFile(editor.getDocument());
|
VirtualFile virFile = FileDocumentManager.getInstance().getFile(editor.getDocument());
|
||||||
if (!IntellijLanguageClient.isExtensionSupported(virFile)) {
|
if (!IntellijLanguageClient.isExtensionSupported(virFile)) {
|
||||||
super.actionPerformed(e);
|
wrapped.actionPerformed(e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
boolean hasSelection = editor.getSelectionModel().hasSelection();
|
boolean hasSelection = editor.getSelectionModel().hasSelection();
|
||||||
|
@ -79,10 +71,5 @@ public class LSPShowReformatDialogAction extends ShowReformatFileDialog implemen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update(AnActionEvent event) {
|
|
||||||
super.update(event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,252 @@
|
||||||
|
/*
|
||||||
|
* 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.lsp.actions;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.lsp.IntellijLanguageClient;
|
||||||
|
import com.falsepattern.zigbrains.lsp.editor.EditorEventManager;
|
||||||
|
import com.falsepattern.zigbrains.lsp.editor.EditorEventManagerBase;
|
||||||
|
import com.intellij.openapi.actionSystem.ActionUpdateThread;
|
||||||
|
import com.intellij.openapi.actionSystem.AnAction;
|
||||||
|
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||||
|
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||||
|
import com.intellij.openapi.actionSystem.OverridingAction;
|
||||||
|
import com.intellij.openapi.actionSystem.ShortcutSet;
|
||||||
|
import com.intellij.psi.PsiDocumentManager;
|
||||||
|
import com.intellij.psi.PsiFile;
|
||||||
|
import lombok.val;
|
||||||
|
import org.jetbrains.annotations.Nls;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public abstract class WrappedAction<T extends AnAction> extends AnAction implements OverridingAction {
|
||||||
|
public final T wrapped;
|
||||||
|
|
||||||
|
// private static class Reflector {
|
||||||
|
// static Field templatePresentation;
|
||||||
|
// static Field myShortcutSet;
|
||||||
|
// static Field myEnabledInModalContext;
|
||||||
|
// static Field myIsDefaultIcon;
|
||||||
|
// static Field myWorksInInjected;
|
||||||
|
// static Field myActionTextOverrides;
|
||||||
|
// static Field mySynonyms;
|
||||||
|
// static Field[] fields;
|
||||||
|
//
|
||||||
|
// static {
|
||||||
|
// val theClass = AnAction.class;
|
||||||
|
// val validFields = new ArrayList<Field>();
|
||||||
|
// try {
|
||||||
|
// templatePresentation = theClass.getDeclaredField("templatePresentation");
|
||||||
|
// templatePresentation.setAccessible(true);
|
||||||
|
// validFields.add(templatePresentation);
|
||||||
|
// } catch (NoSuchFieldException e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
// try {
|
||||||
|
// myShortcutSet = theClass.getDeclaredField("myShortcutSet");
|
||||||
|
// myShortcutSet.setAccessible(true);
|
||||||
|
// validFields.add(myShortcutSet);
|
||||||
|
// } catch (NoSuchFieldException e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
// try {
|
||||||
|
// myEnabledInModalContext = theClass.getDeclaredField("myEnabledInModalContext");
|
||||||
|
// myEnabledInModalContext.setAccessible(true);
|
||||||
|
// validFields.add(myEnabledInModalContext);
|
||||||
|
// } catch (NoSuchFieldException e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
// try {
|
||||||
|
// myIsDefaultIcon = theClass.getDeclaredField("myIsDefaultIcon");
|
||||||
|
// myIsDefaultIcon.setAccessible(true);
|
||||||
|
// validFields.add(myIsDefaultIcon);
|
||||||
|
// } catch (NoSuchFieldException e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
// try {
|
||||||
|
// myWorksInInjected = theClass.getDeclaredField("myWorksInInjected");
|
||||||
|
// myWorksInInjected.setAccessible(true);
|
||||||
|
// validFields.add(myWorksInInjected);
|
||||||
|
// } catch (NoSuchFieldException e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
// try {
|
||||||
|
// myActionTextOverrides = theClass.getDeclaredField("myActionTextOverrides");
|
||||||
|
// myActionTextOverrides.setAccessible(true);
|
||||||
|
// validFields.add(myActionTextOverrides);
|
||||||
|
// } catch (NoSuchFieldException e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
// try {
|
||||||
|
// mySynonyms = theClass.getDeclaredField("mySynonyms");
|
||||||
|
// mySynonyms.setAccessible(true);
|
||||||
|
// validFields.add(mySynonyms);
|
||||||
|
// } catch (NoSuchFieldException e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
// fields = validFields.toArray(new Field[0]);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
public WrappedAction(T wrapped) {
|
||||||
|
this.wrapped = wrapped;
|
||||||
|
// if (Reflector.fields != null) {
|
||||||
|
// for (val field: Reflector.fields) {
|
||||||
|
// assimilate(field);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
private void assimilate(Field field) {
|
||||||
|
if (field == null)
|
||||||
|
return;
|
||||||
|
try {
|
||||||
|
field.set(this, field.get(wrapped));
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDumbAware() {
|
||||||
|
return wrapped.isDumbAware();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ActionUpdateThread getActionUpdateThread() {
|
||||||
|
return wrapped.getActionUpdateThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean displayTextInToolbar() {
|
||||||
|
return super.displayTextInToolbar();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useSmallerFontForTextInToolbar() {
|
||||||
|
return super.useSmallerFontForTextInToolbar();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setShortcutSet(@NotNull ShortcutSet shortcutSet) {
|
||||||
|
super.setShortcutSet(shortcutSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefaultIcon(boolean isDefaultIconSet) {
|
||||||
|
wrapped.setDefaultIcon(isDefaultIconSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDefaultIcon() {
|
||||||
|
return wrapped.isDefaultIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInjectedContext(boolean worksInInjected) {
|
||||||
|
wrapped.setInjectedContext(worksInInjected);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInInjectedContext() {
|
||||||
|
return wrapped.isInInjectedContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addSynonym(@NotNull Supplier<@Nls String> text) {
|
||||||
|
wrapped.addSynonym(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<Supplier<String>> getSynonyms() {
|
||||||
|
return wrapped.getSynonyms();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void update(@NotNull AnActionEvent e) {
|
||||||
|
val manager = tryGetEventManager(e);
|
||||||
|
if (manager == null) {
|
||||||
|
wrapped.update(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
val file = tryGetPSIFileLSPAware(manager);
|
||||||
|
if (file == null) {
|
||||||
|
wrapped.update(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateLSP(e, manager, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void beforeActionPerformedUpdate(@NotNull AnActionEvent e) {
|
||||||
|
val manager = tryGetEventManager(e);
|
||||||
|
if (manager == null) {
|
||||||
|
wrapped.beforeActionPerformedUpdate(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
val file = tryGetPSIFileLSPAware(manager);
|
||||||
|
if (file == null) {
|
||||||
|
wrapped.beforeActionPerformedUpdate(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
beforeActionPerformedUpdateLSP(e, manager, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void actionPerformed(@NotNull AnActionEvent e) {
|
||||||
|
val manager = tryGetEventManager(e);
|
||||||
|
if (manager == null) {
|
||||||
|
wrapped.actionPerformed(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
val file = tryGetPSIFileLSPAware(manager);
|
||||||
|
if (file == null) {
|
||||||
|
wrapped.actionPerformed(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
actionPerformedLSP(e, manager, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static EditorEventManager tryGetEventManager(AnActionEvent e) {
|
||||||
|
val editor = e.getData(CommonDataKeys.EDITOR);
|
||||||
|
if (editor == null)
|
||||||
|
return null;
|
||||||
|
return EditorEventManagerBase.forEditor(editor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PsiFile tryGetPSIFileLSPAware(EditorEventManager manager) {
|
||||||
|
val project = manager.getProject();
|
||||||
|
val editor = manager.editor;
|
||||||
|
if (project == null)
|
||||||
|
return null;
|
||||||
|
val file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
|
||||||
|
if (file == null || !IntellijLanguageClient.isExtensionSupported(file.getVirtualFile()))
|
||||||
|
return null;
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void actionPerformedLSP(AnActionEvent e, EditorEventManager manager, PsiFile file);
|
||||||
|
|
||||||
|
protected void beforeActionPerformedUpdateLSP(AnActionEvent e, EditorEventManager manager, PsiFile file) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updateLSP(AnActionEvent e, EditorEventManager manager, PsiFile file) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,7 +47,6 @@ import com.intellij.openapi.project.ProjectUtil;
|
||||||
import com.intellij.openapi.ui.MessageType;
|
import com.intellij.openapi.ui.MessageType;
|
||||||
import com.intellij.openapi.ui.Messages;
|
import com.intellij.openapi.ui.Messages;
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
import com.intellij.openapi.wm.impl.status.widget.StatusBarWidgetsManager;
|
|
||||||
import com.intellij.psi.PsiDocumentManager;
|
import com.intellij.psi.PsiDocumentManager;
|
||||||
import com.intellij.psi.PsiFile;
|
import com.intellij.psi.PsiFile;
|
||||||
import com.intellij.remoteServer.util.CloudNotifier;
|
import com.intellij.remoteServer.util.CloudNotifier;
|
||||||
|
@ -261,7 +260,7 @@ public class LanguageServerWrapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyResult(Timeouts timeouts, boolean success) {
|
public void notifyResult(Timeouts timeouts, boolean success) {
|
||||||
getWidget().ifPresent(widget -> widget.notifyResult(timeouts, success));
|
getWidgets().forEach(widget -> widget.notifyResult(timeouts, success));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifySuccess(Timeouts timeouts) {
|
public void notifySuccess(Timeouts timeouts) {
|
||||||
|
@ -624,7 +623,7 @@ public class LanguageServerWrapper {
|
||||||
|
|
||||||
private void setStatus(ServerStatus status) {
|
private void setStatus(ServerStatus status) {
|
||||||
this.status = status;
|
this.status = status;
|
||||||
getWidget().ifPresent(widget -> widget.setStatus(status));
|
getWidgets().forEach(widget -> widget.setStatus(status));
|
||||||
synchronized (shutdownHook) {
|
synchronized (shutdownHook) {
|
||||||
if ((status == STARTED || status == INITIALIZED) && shutdownHook.get() == null) {
|
if ((status == STARTED || status == INITIALIZED) && shutdownHook.get() == null) {
|
||||||
shutdownHook.set(new Thread(() -> {
|
shutdownHook.set(new Thread(() -> {
|
||||||
|
@ -694,10 +693,6 @@ public class LanguageServerWrapper {
|
||||||
return connected;
|
return connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeWidget() {
|
|
||||||
getWidget().ifPresent(LSPServerStatusWidget::dispose);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disconnects an editor from the LanguageServer
|
* Disconnects an editor from the LanguageServer
|
||||||
*
|
*
|
||||||
|
@ -726,7 +721,7 @@ public class LanguageServerWrapper {
|
||||||
if (connectedEditors.isEmpty()) {
|
if (connectedEditors.isEmpty()) {
|
||||||
stop(true);
|
stop(true);
|
||||||
|
|
||||||
getWidget().ifPresent(widget -> widget.setStatus(ServerStatus.NONEXISTENT));
|
getWidgets().forEach(widget -> widget.setStatus(ServerStatus.NONEXISTENT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -764,13 +759,12 @@ public class LanguageServerWrapper {
|
||||||
if (connectedEditors.isEmpty()) {
|
if (connectedEditors.isEmpty()) {
|
||||||
stop(true);
|
stop(true);
|
||||||
|
|
||||||
getWidget().ifPresent(widget -> widget.setStatus(ServerStatus.NONEXISTENT));
|
getWidgets().forEach(widget -> widget.setStatus(ServerStatus.NONEXISTENT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeServerWrapper() {
|
public void removeServerWrapper() {
|
||||||
stop(true);
|
stop(true);
|
||||||
removeWidget();
|
|
||||||
IntellijLanguageClient.removeWrapper(this);
|
IntellijLanguageClient.removeWrapper(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -805,13 +799,8 @@ public class LanguageServerWrapper {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<LSPServerStatusWidget> getWidget() {
|
private List<LSPServerStatusWidget> getWidgets() {
|
||||||
LSPServerStatusWidgetFactory factory = ((LSPServerStatusWidgetFactory) project.getService(StatusBarWidgetsManager.class).findWidgetFactory("LSP"));
|
return Optional.ofNullable(project.getUserData(LSPServerStatusWidgetFactory.LSP_WIDGETS)).orElse(List.of());
|
||||||
if (factory != null) {
|
|
||||||
return Optional.of(factory.getWidget(project));
|
|
||||||
} else {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -143,20 +143,17 @@ public class LSPAnnotator extends ExternalAnnotator<Object, Object> {
|
||||||
annotations.forEach(annotation -> {
|
annotations.forEach(annotation -> {
|
||||||
if (annotation.getQuickFixes() != null && !annotation.getQuickFixes().isEmpty()) {
|
if (annotation.getQuickFixes() != null && !annotation.getQuickFixes().isEmpty()) {
|
||||||
AnnotationBuilder builder = holder.newAnnotation(annotation.getSeverity(), annotation.getMessage());
|
AnnotationBuilder builder = holder.newAnnotation(annotation.getSeverity(), annotation.getMessage());
|
||||||
boolean range = true;
|
builder = builder.range(TextRange.create(annotation.getStartOffset(), annotation.getEndOffset()));
|
||||||
for (Annotation.QuickFixInfo quickFixInfo : annotation.getQuickFixes()) {
|
for (Annotation.QuickFixInfo quickFixInfo : annotation.getQuickFixes()) {
|
||||||
if (range) {
|
builder = builder.newFix(quickFixInfo.quickFix).range(quickFixInfo.textRange).key(quickFixInfo.key).registerFix();
|
||||||
builder = builder.range(quickFixInfo.textRange);
|
|
||||||
range = false;
|
|
||||||
}
|
|
||||||
builder = builder.withFix(quickFixInfo.quickFix);
|
|
||||||
}
|
}
|
||||||
builder.create();
|
builder.create();
|
||||||
} else if (requests.containsKey(annotation)) {
|
} else if (requests.containsKey(annotation)) {
|
||||||
AnnotationBuilder builder = holder.newAnnotation(annotation.getSeverity(), annotation.getMessage());
|
AnnotationBuilder builder = holder.newAnnotation(annotation.getSeverity(), annotation.getMessage());
|
||||||
|
builder = builder.range(TextRange.create(annotation.getStartOffset(), annotation.getEndOffset()));
|
||||||
var request = requests.remove(annotation);
|
var request = requests.remove(annotation);
|
||||||
for (var quickFixInfo: request) {
|
for (var quickFixInfo: request) {
|
||||||
builder = builder.withFix(quickFixInfo.action());
|
builder = builder.newFix(quickFixInfo.action()).range(quickFixInfo.range()).registerFix();
|
||||||
}
|
}
|
||||||
builder.create();
|
builder.create();
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,6 @@ public class LSPProjectManagerListener implements ProjectManagerListener {
|
||||||
Set<LanguageServerWrapper> languageServerWrappers = IntellijLanguageClient.getAllServerWrappersFor(FileUtils.projectToUri(project));
|
Set<LanguageServerWrapper> languageServerWrappers = IntellijLanguageClient.getAllServerWrappersFor(FileUtils.projectToUri(project));
|
||||||
languageServerWrappers.forEach(wrapper -> {
|
languageServerWrappers.forEach(wrapper -> {
|
||||||
wrapper.stop(false);
|
wrapper.stop(false);
|
||||||
wrapper.removeWidget();
|
|
||||||
IntellijLanguageClient.removeWrapper(wrapper);
|
IntellijLanguageClient.removeWrapper(wrapper);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,12 @@
|
||||||
*/
|
*/
|
||||||
package com.falsepattern.zigbrains.lsp.statusbar;
|
package com.falsepattern.zigbrains.lsp.statusbar;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.lsp.IntellijLanguageClient;
|
||||||
import com.falsepattern.zigbrains.lsp.client.languageserver.ServerStatus;
|
import com.falsepattern.zigbrains.lsp.client.languageserver.ServerStatus;
|
||||||
import com.falsepattern.zigbrains.lsp.client.languageserver.wrapper.LanguageServerWrapper;
|
import com.falsepattern.zigbrains.lsp.client.languageserver.wrapper.LanguageServerWrapper;
|
||||||
import com.falsepattern.zigbrains.lsp.contributors.icon.LSPDefaultIconProvider;
|
import com.falsepattern.zigbrains.lsp.contributors.icon.LSPDefaultIconProvider;
|
||||||
import com.falsepattern.zigbrains.lsp.requests.Timeouts;
|
import com.falsepattern.zigbrains.lsp.requests.Timeouts;
|
||||||
import com.falsepattern.zigbrains.lsp.utils.GUIUtils;
|
import com.falsepattern.zigbrains.lsp.utils.GUIUtils;
|
||||||
import com.intellij.ide.DataManager;
|
|
||||||
import com.intellij.openapi.actionSystem.AnAction;
|
import com.intellij.openapi.actionSystem.AnAction;
|
||||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||||
import com.intellij.openapi.actionSystem.DataContext;
|
import com.intellij.openapi.actionSystem.DataContext;
|
||||||
|
@ -30,40 +30,67 @@ import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.openapi.ui.Messages;
|
import com.intellij.openapi.ui.Messages;
|
||||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||||
import com.intellij.openapi.ui.popup.ListPopup;
|
import com.intellij.openapi.ui.popup.ListPopup;
|
||||||
import com.intellij.openapi.wm.StatusBar;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
import com.intellij.openapi.wm.StatusBarWidget;
|
import com.intellij.openapi.wm.StatusBarWidget;
|
||||||
import com.intellij.openapi.wm.WindowManager;
|
import com.intellij.openapi.wm.impl.status.EditorBasedStatusBarPopup;
|
||||||
import com.intellij.ui.awt.RelativePoint;
|
import lombok.val;
|
||||||
import com.intellij.util.Consumer;
|
|
||||||
import org.apache.commons.lang3.tuple.MutablePair;
|
import org.apache.commons.lang3.tuple.MutablePair;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import javax.swing.BoxLayout;
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Dimension;
|
import java.lang.ref.WeakReference;
|
||||||
import java.awt.Point;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class LSPServerStatusWidget implements StatusBarWidget {
|
public class LSPServerStatusWidget extends EditorBasedStatusBarPopup {
|
||||||
|
|
||||||
private final Map<Timeouts, Pair<Integer, Integer>> timeouts = new HashMap<>();
|
private final Map<Timeouts, Pair<Integer, Integer>> timeouts = new HashMap<>();
|
||||||
private final Project project;
|
|
||||||
private final String projectName;
|
private final String projectName;
|
||||||
private ServerStatus status = ServerStatus.NONEXISTENT;
|
private ServerStatus status = ServerStatus.NONEXISTENT;
|
||||||
|
|
||||||
|
private static final List<WeakReference<LSPServerStatusWidget>> widgets = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
private static final ScheduledExecutorService refresher = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
static {
|
||||||
|
refresher.scheduleWithFixedDelay(() -> {
|
||||||
|
synchronized (widgets) {
|
||||||
|
val iter = widgets.iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
val weakWidget = iter.next();
|
||||||
|
val widget = weakWidget.get();
|
||||||
|
if (widget == null) {
|
||||||
|
iter.remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
widget.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 1, 1, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Project project() {
|
||||||
|
return super.getProject();
|
||||||
|
}
|
||||||
|
|
||||||
LSPServerStatusWidget(Project project) {
|
LSPServerStatusWidget(Project project) {
|
||||||
this.project = project;
|
super(project, false);
|
||||||
this.projectName = project.getName();
|
this.projectName = project.getName();
|
||||||
|
|
||||||
for (Timeouts t : Timeouts.values()) {
|
for (Timeouts t : Timeouts.values()) {
|
||||||
timeouts.put(t, new MutablePair<>(0, 0));
|
timeouts.put(t, new MutablePair<>(0, 0));
|
||||||
}
|
}
|
||||||
|
widgets.add(new WeakReference<>(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyResult(Timeouts timeout, Boolean success) {
|
public void notifyResult(Timeouts timeout, Boolean success) {
|
||||||
|
@ -75,14 +102,6 @@ public class LSPServerStatusWidget implements StatusBarWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IconPresentation getPresentation() {
|
|
||||||
return new IconPresentation();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void install(@NotNull StatusBar statusBar) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the status of the server
|
* Sets the status of the server
|
||||||
*
|
*
|
||||||
|
@ -90,37 +109,52 @@ public class LSPServerStatusWidget implements StatusBarWidget {
|
||||||
*/
|
*/
|
||||||
public void setStatus(ServerStatus status) {
|
public void setStatus(ServerStatus status) {
|
||||||
this.status = status;
|
this.status = status;
|
||||||
updateWidget();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateWidget() {
|
|
||||||
WindowManager manager = WindowManager.getInstance();
|
|
||||||
if (manager != null && project != null && !project.isDisposed()) {
|
|
||||||
StatusBar statusBar = manager.getStatusBar(project);
|
|
||||||
if (statusBar != null) {
|
|
||||||
statusBar.updateWidget(ID());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dispose() {}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public String ID() {
|
public String ID() {
|
||||||
return "LSP";
|
return "LSP";
|
||||||
}
|
}
|
||||||
|
|
||||||
public Project getProject() {
|
@NotNull
|
||||||
return project;
|
@Override
|
||||||
|
protected StatusBarWidget createInstance(@NotNull Project project) {
|
||||||
|
return new LSPServerStatusWidget(project);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LSPServerStatusPanel component;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
protected JPanel createComponent() {
|
||||||
|
component = new LSPServerStatusPanel();
|
||||||
|
updateComponent();
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateComponent(@NotNull EditorBasedStatusBarPopup.WidgetState state) {
|
||||||
|
updateComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateComponent() {
|
||||||
|
if (component != null) {
|
||||||
|
component.setToolTipText(getTooltipText());
|
||||||
|
component.setIcon(getIcon());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class IconPresentation implements StatusBarWidget.IconPresentation {
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Icon getIcon() {
|
public WidgetPresentation getPresentation() {
|
||||||
LanguageServerWrapper wrapper = LanguageServerWrapper.forProject(project);
|
return super.getPresentation();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Icon getIcon() {
|
||||||
|
LanguageServerWrapper wrapper = LanguageServerWrapper.forProject(project());
|
||||||
Map<ServerStatus, Icon> icons = new LSPDefaultIconProvider().getStatusIcons();
|
Map<ServerStatus, Icon> icons = new LSPDefaultIconProvider().getStatusIcons();
|
||||||
if (wrapper != null) {
|
if (wrapper != null) {
|
||||||
icons = GUIUtils.getIconProviderFor(wrapper.getServerDefinition())
|
icons = GUIUtils.getIconProviderFor(wrapper.getServerDefinition())
|
||||||
|
@ -129,20 +163,26 @@ public class LSPServerStatusWidget implements StatusBarWidget {
|
||||||
return icons.get(status);
|
return icons.get(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("UsagesOfObsoleteApi")
|
private String getTooltipText() {
|
||||||
|
LanguageServerWrapper wrapper = LanguageServerWrapper.forProject(project());
|
||||||
|
if (wrapper == null) {
|
||||||
|
return "Language server, project " + projectName;
|
||||||
|
} else {
|
||||||
|
return "Language server for extension " + wrapper.getServerDefinition().ext + ", project " + projectName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isEmpty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Consumer<MouseEvent> getClickConsumer() {
|
protected ListPopup createPopup(@NotNull DataContext dataContext) {
|
||||||
return (MouseEvent t) -> {
|
var wrapper = LanguageServerWrapper.forProject(project());
|
||||||
JBPopupFactory.ActionSelectionAid mnemonics = JBPopupFactory.ActionSelectionAid.MNEMONICS;
|
|
||||||
Component component = t.getComponent();
|
|
||||||
var wrapper = LanguageServerWrapper.forProject(project);
|
|
||||||
if (wrapper == null) {
|
if (wrapper == null) {
|
||||||
var popup = JBPopupFactory.getInstance().createMessage("No language server active.");
|
return null;
|
||||||
Dimension dimension = popup.getContent().getPreferredSize();
|
|
||||||
Point at = new Point(0, -dimension.height);
|
|
||||||
popup.show(new RelativePoint(t.getComponent(), at));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
List<AnAction> actions = new ArrayList<>();
|
List<AnAction> actions = new ArrayList<>();
|
||||||
if (wrapper.getStatus() == ServerStatus.INITIALIZED) {
|
if (wrapper.getStatus() == ServerStatus.INITIALIZED) {
|
||||||
|
@ -152,17 +192,31 @@ public class LSPServerStatusWidget implements StatusBarWidget {
|
||||||
|
|
||||||
actions.add(new Restart());
|
actions.add(new Restart());
|
||||||
|
|
||||||
|
JBPopupFactory.ActionSelectionAid mnemonics = JBPopupFactory.ActionSelectionAid.MNEMONICS;
|
||||||
String title = "Server Actions";
|
String title = "Server Actions";
|
||||||
DataContext context = DataManager.getInstance().getDataContext(component);
|
|
||||||
DefaultActionGroup group = new DefaultActionGroup(actions);
|
DefaultActionGroup group = new DefaultActionGroup(actions);
|
||||||
ListPopup popup = JBPopupFactory.getInstance()
|
return JBPopupFactory.getInstance()
|
||||||
.createActionGroupPopup(title, group, context, mnemonics, true);
|
.createActionGroupPopup(title, group, dataContext, mnemonics, true);
|
||||||
Dimension dimension = popup.getContent().getPreferredSize();
|
|
||||||
Point at = new Point(0, -dimension.height);
|
|
||||||
popup.show(new RelativePoint(t.getComponent(), at));
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
protected WidgetState getWidgetState(@Nullable VirtualFile virtualFile) {
|
||||||
|
if (virtualFile == null) {
|
||||||
|
return WidgetState.HIDDEN;
|
||||||
|
}
|
||||||
|
val manager = IntellijLanguageClient.getExtensionManagerFor(virtualFile.getExtension());
|
||||||
|
if (manager != null) {
|
||||||
|
val ws = new WidgetState(getTooltipText(), null, true);
|
||||||
|
ws.setIcon(getIcon());
|
||||||
|
return ws;
|
||||||
|
} else {
|
||||||
|
return WidgetState.HIDDEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ShowConnectedFiles extends AnAction implements DumbAware {
|
class ShowConnectedFiles extends AnAction implements DumbAware {
|
||||||
ShowConnectedFiles() {
|
ShowConnectedFiles() {
|
||||||
super("&Show Connected Files", "Show the files connected to the server", null);
|
super("&Show Connected Files", "Show the files connected to the server", null);
|
||||||
|
@ -170,7 +224,7 @@ public class LSPServerStatusWidget implements StatusBarWidget {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||||
var wrapper = LanguageServerWrapper.forProject(project);
|
var wrapper = LanguageServerWrapper.forProject(project());
|
||||||
if (wrapper == null) {
|
if (wrapper == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -220,22 +274,29 @@ public class LSPServerStatusWidget implements StatusBarWidget {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(@NotNull AnActionEvent anActionEvent) {
|
public void actionPerformed(@NotNull AnActionEvent anActionEvent) {
|
||||||
var wrapper = LanguageServerWrapper.forProject(project);
|
var wrapper = LanguageServerWrapper.forProject(project());
|
||||||
if (wrapper != null) {
|
if (wrapper != null) {
|
||||||
wrapper.restart();
|
wrapper.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
private class LSPServerStatusPanel extends JPanel {
|
||||||
|
private final JLabel myIconLabel;
|
||||||
|
|
||||||
|
LSPServerStatusPanel() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
setOpaque(false);
|
||||||
|
setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
|
||||||
|
setAlignmentY(Component.CENTER_ALIGNMENT);
|
||||||
|
myIconLabel = new JLabel("");
|
||||||
|
|
||||||
|
add(myIconLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void setIcon(@Nullable Icon icon) {
|
||||||
public String getTooltipText() {
|
myIconLabel.setIcon(icon);
|
||||||
LanguageServerWrapper wrapper = LanguageServerWrapper.forProject(project);
|
myIconLabel.setVisible(icon != null);
|
||||||
if (wrapper == null) {
|
|
||||||
return "Language server, project " + projectName;
|
|
||||||
} else {
|
|
||||||
return "Language server for extension " + wrapper.getServerDefinition().ext + ", project " + projectName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,19 +16,19 @@
|
||||||
package com.falsepattern.zigbrains.lsp.statusbar;
|
package com.falsepattern.zigbrains.lsp.statusbar;
|
||||||
|
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.openapi.wm.StatusBar;
|
import com.intellij.openapi.util.Key;
|
||||||
import com.intellij.openapi.wm.StatusBarWidget;
|
import com.intellij.openapi.wm.StatusBarWidget;
|
||||||
import com.intellij.openapi.wm.StatusBarWidgetFactory;
|
import com.intellij.openapi.wm.impl.status.widget.StatusBarEditorBasedWidgetFactory;
|
||||||
|
import lombok.val;
|
||||||
import org.jetbrains.annotations.Nls;
|
import org.jetbrains.annotations.Nls;
|
||||||
import org.jetbrains.annotations.NonNls;
|
import org.jetbrains.annotations.NonNls;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.List;
|
||||||
|
|
||||||
public class LSPServerStatusWidgetFactory implements StatusBarWidgetFactory {
|
|
||||||
private final Map<Project, LSPServerStatusWidget> widgetForProject = new HashMap<>();
|
|
||||||
|
|
||||||
|
public class LSPServerStatusWidgetFactory extends StatusBarEditorBasedWidgetFactory {
|
||||||
|
public static final Key<List<LSPServerStatusWidget>> LSP_WIDGETS = Key.create("ZB_LSP_KEYS");
|
||||||
@Override
|
@Override
|
||||||
public @NonNls
|
public @NonNls
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@ -44,29 +44,26 @@ public class LSPServerStatusWidgetFactory implements StatusBarWidgetFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAvailable(@NotNull Project project) {
|
public @NotNull StatusBarWidget createWidget(@NotNull Project project) {
|
||||||
return true;
|
var keys = project.getUserData(LSP_WIDGETS);
|
||||||
|
if (keys == null) {
|
||||||
|
keys = new ArrayList<>();
|
||||||
|
project.putUserData(LSP_WIDGETS, keys);
|
||||||
|
}
|
||||||
|
val widget = new LSPServerStatusWidget(project);
|
||||||
|
keys.add(widget);
|
||||||
|
return widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public void disposeWidget(@NotNull StatusBarWidget widget) {
|
||||||
StatusBarWidget createWidget(@NotNull Project project) {
|
if (widget instanceof LSPServerStatusWidget w) {
|
||||||
return widgetForProject.computeIfAbsent(project, (k) -> new LSPServerStatusWidget(project));
|
val project = w.project();
|
||||||
}
|
val keys = project.getUserData(LSP_WIDGETS);
|
||||||
|
if (keys != null) {
|
||||||
@Override
|
keys.remove(widget);
|
||||||
public void disposeWidget(@NotNull StatusBarWidget statusBarWidget) {
|
|
||||||
if (statusBarWidget instanceof LSPServerStatusWidget) {
|
|
||||||
widgetForProject.remove(((LSPServerStatusWidget) statusBarWidget).getProject());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
super.disposeWidget(widget);
|
||||||
@Override
|
|
||||||
public boolean canBeEnabledOn(@NotNull StatusBar statusBar) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LSPServerStatusWidget getWidget(Project project) {
|
|
||||||
return widgetForProject.get(project);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||||
import com.intellij.openapi.fileEditor.FileEditor;
|
import com.intellij.openapi.fileEditor.FileEditor;
|
||||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||||
import com.intellij.openapi.fileEditor.TextEditor;
|
import com.intellij.openapi.fileEditor.TextEditor;
|
||||||
import com.intellij.openapi.fileTypes.FileType;
|
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.openapi.project.ProjectManager;
|
import com.intellij.openapi.project.ProjectManager;
|
||||||
import com.intellij.openapi.project.ProjectUtil;
|
import com.intellij.openapi.project.ProjectUtil;
|
||||||
|
|
|
@ -59,7 +59,7 @@ public abstract class ProfileStateBase<T extends ZigExecConfigBase<T>> extends C
|
||||||
workingDirectory.getPath().ifPresent(x -> cli.setWorkDirectory(x.toFile()));
|
workingDirectory.getPath().ifPresent(x -> cli.setWorkDirectory(x.toFile()));
|
||||||
cli.setCharset(StandardCharsets.UTF_8);
|
cli.setCharset(StandardCharsets.UTF_8);
|
||||||
cli.setRedirectErrorStream(true);
|
cli.setRedirectErrorStream(true);
|
||||||
cli.addParameters(debug ? configuration.buildDebugCommandLineArgs() : configuration.buildCommandLineArgs());
|
cli.addParameters(configuration.buildCommandLineArgs(debug));
|
||||||
return cli;
|
return cli;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,11 +63,7 @@ public abstract class ZigExecConfigBase<T extends ZigExecConfigBase<T>> extends
|
||||||
getConfigurables().forEach(cfg -> cfg.writeExternal(element));
|
getConfigurables().forEach(cfg -> cfg.writeExternal(element));
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract String[] buildCommandLineArgs() throws ExecutionException;
|
public abstract List<String> buildCommandLineArgs(boolean debug) throws ExecutionException;
|
||||||
|
|
||||||
public String[] buildDebugCommandLineArgs() throws ExecutionException {
|
|
||||||
return buildCommandLineArgs();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T clone() {
|
public T clone() {
|
||||||
|
|
|
@ -20,6 +20,7 @@ import com.falsepattern.zigbrains.common.ZBFeatures;
|
||||||
import com.falsepattern.zigbrains.common.util.CollectionUtil;
|
import com.falsepattern.zigbrains.common.util.CollectionUtil;
|
||||||
import com.falsepattern.zigbrains.project.execution.base.ZigConfigEditor;
|
import com.falsepattern.zigbrains.project.execution.base.ZigConfigEditor;
|
||||||
import com.falsepattern.zigbrains.project.execution.base.ZigExecConfigBase;
|
import com.falsepattern.zigbrains.project.execution.base.ZigExecConfigBase;
|
||||||
|
import com.falsepattern.zigbrains.project.util.CLIUtil;
|
||||||
import com.intellij.execution.ExecutionException;
|
import com.intellij.execution.ExecutionException;
|
||||||
import com.intellij.execution.Executor;
|
import com.intellij.execution.Executor;
|
||||||
import com.intellij.execution.configurations.ConfigurationFactory;
|
import com.intellij.execution.configurations.ConfigurationFactory;
|
||||||
|
@ -44,30 +45,28 @@ public class ZigExecConfigBuild extends ZigExecConfigBase<ZigExecConfigBuild> {
|
||||||
super(project, factory, "Zig Build");
|
super(project, factory, "Zig Build");
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] buildWithSteps(String[] steps) throws ExecutionException {
|
|
||||||
val base = new String[]{"build", "--color", colored.value ? "on" : "off"};
|
|
||||||
return CollectionUtil.concat(base, steps, extraArgs.args).toArray(String[]::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] buildCommandLineArgs() throws ExecutionException {
|
public List<String> buildCommandLineArgs(boolean debug) throws ExecutionException {
|
||||||
return buildWithSteps(buildSteps.args);
|
val result = new ArrayList<String>();
|
||||||
}
|
result.add("build");
|
||||||
|
var steps = List.of(buildSteps.args);
|
||||||
@Override
|
if (debug) {
|
||||||
public String[] buildDebugCommandLineArgs() throws ExecutionException {
|
|
||||||
var steps = buildSteps.args;
|
|
||||||
val truncatedSteps = new ArrayList<String>();
|
val truncatedSteps = new ArrayList<String>();
|
||||||
for (int i = 0; i < steps.length; i++) {
|
for (int i = 0, size = steps.size(); i < size; i++) {
|
||||||
if (steps[i].equals("run")) {
|
if (steps.get(i).equals("run")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (steps[i].equals("test")) {
|
if (steps.get(i).equals("test")) {
|
||||||
throw new ExecutionException("Debugging \"zig build test\" is not supported yet.");
|
throw new ExecutionException("Debugging \"zig build test\" is not supported yet.");
|
||||||
}
|
}
|
||||||
truncatedSteps.add(steps[i]);
|
truncatedSteps.add(steps.get(i));
|
||||||
}
|
}
|
||||||
return buildWithSteps(truncatedSteps.toArray(String[]::new));
|
steps = truncatedSteps;
|
||||||
|
}
|
||||||
|
result.addAll(steps);
|
||||||
|
result.addAll(CLIUtil.colored(colored.value));
|
||||||
|
result.addAll(List.of(extraArgs.args));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -19,6 +19,7 @@ package com.falsepattern.zigbrains.project.execution.run;
|
||||||
import com.falsepattern.zigbrains.common.util.CollectionUtil;
|
import com.falsepattern.zigbrains.common.util.CollectionUtil;
|
||||||
import com.falsepattern.zigbrains.project.execution.base.ZigConfigEditor;
|
import com.falsepattern.zigbrains.project.execution.base.ZigConfigEditor;
|
||||||
import com.falsepattern.zigbrains.project.execution.base.ZigExecConfigBase;
|
import com.falsepattern.zigbrains.project.execution.base.ZigExecConfigBase;
|
||||||
|
import com.falsepattern.zigbrains.project.util.CLIUtil;
|
||||||
import com.intellij.execution.Executor;
|
import com.intellij.execution.Executor;
|
||||||
import com.intellij.execution.configurations.ConfigurationFactory;
|
import com.intellij.execution.configurations.ConfigurationFactory;
|
||||||
import com.intellij.execution.runners.ExecutionEnvironment;
|
import com.intellij.execution.runners.ExecutionEnvironment;
|
||||||
|
@ -28,6 +29,7 @@ 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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
@ -41,17 +43,19 @@ public class ZigExecConfigRun extends ZigExecConfigBase<ZigExecConfigRun> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] buildCommandLineArgs() {
|
public List<String> buildCommandLineArgs(boolean debug) {
|
||||||
return CollectionUtil.concat(new String[]{"run", "--color", colored.value ? "on" : "off", filePath.getPathOrThrow().toString(), "-O", optimization.level.name(), "--"}, exeArgs.args).toArray(String[]::new);
|
val result = new ArrayList<String>();
|
||||||
|
result.add("run");
|
||||||
|
result.addAll(CLIUtil.colored(colored.value));
|
||||||
|
result.add(filePath.getPathOrThrow().toString());
|
||||||
|
if (!debug || optimization.forced) {
|
||||||
|
result.addAll(List.of("-O", optimization.level.name()));
|
||||||
}
|
}
|
||||||
|
if (!debug) {
|
||||||
@Override
|
result.add("--");
|
||||||
public String[] buildDebugCommandLineArgs() {
|
result.addAll(List.of(exeArgs.args));
|
||||||
if (optimization.forced) {
|
|
||||||
return new String[]{"build-exe", "--color", colored.value ? "on" : "off", filePath.getPathOrThrow().toString(), "-O", optimization.level.name()};
|
|
||||||
} else {
|
|
||||||
return new String[]{"build-exe", "--color", colored.value ? "on" : "off", filePath.getPathOrThrow().toString()};
|
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -20,6 +20,7 @@ import com.falsepattern.zigbrains.common.util.CollectionUtil;
|
||||||
import com.falsepattern.zigbrains.project.execution.base.ProfileStateBase;
|
import com.falsepattern.zigbrains.project.execution.base.ProfileStateBase;
|
||||||
import com.falsepattern.zigbrains.project.execution.base.ZigConfigEditor;
|
import com.falsepattern.zigbrains.project.execution.base.ZigConfigEditor;
|
||||||
import com.falsepattern.zigbrains.project.execution.base.ZigExecConfigBase;
|
import com.falsepattern.zigbrains.project.execution.base.ZigExecConfigBase;
|
||||||
|
import com.falsepattern.zigbrains.project.util.CLIUtil;
|
||||||
import com.intellij.execution.Executor;
|
import com.intellij.execution.Executor;
|
||||||
import com.intellij.execution.configurations.ConfigurationFactory;
|
import com.intellij.execution.configurations.ConfigurationFactory;
|
||||||
import com.intellij.execution.runners.ExecutionEnvironment;
|
import com.intellij.execution.runners.ExecutionEnvironment;
|
||||||
|
@ -29,6 +30,7 @@ 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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
@ -41,17 +43,18 @@ public class ZigExecConfigTest extends ZigExecConfigBase<ZigExecConfigTest> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] buildCommandLineArgs() {
|
public List<String> buildCommandLineArgs(boolean debug) {
|
||||||
return new String[]{"test", "--color", colored.value ? "on" : "off", filePath.getPathOrThrow().toString(), "-O", optimization.level.name()};
|
val result = new ArrayList<String>();
|
||||||
|
result.add("test");
|
||||||
|
result.addAll(CLIUtil.colored(colored.value));
|
||||||
|
result.add(filePath.getPathOrThrow().toString());
|
||||||
|
if (!debug || optimization.forced) {
|
||||||
|
result.addAll(List.of("-O", optimization.level.name()));
|
||||||
}
|
}
|
||||||
|
if (debug) {
|
||||||
@Override
|
result.add("--test-no-exec");
|
||||||
public String[] buildDebugCommandLineArgs() {
|
|
||||||
if (optimization.forced) {
|
|
||||||
return new String[]{"test", "--color", colored.value ? "on" : "off", filePath.getPathOrThrow().toString(), "--test-no-exec", "-O", optimization.level.name()};
|
|
||||||
} else {
|
|
||||||
return new String[]{"test", "--color", colored.value ? "on" : "off", filePath.getPathOrThrow().toString(), "--test-no-exec"};
|
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* 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.project.ide.config;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.common.MultiConfigurable;
|
||||||
|
import com.falsepattern.zigbrains.project.ide.project.ZigProjectConfigurable;
|
||||||
|
import com.falsepattern.zigbrains.zig.settings.ZLSSettingsConfigurable;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.intellij.openapi.util.NlsContexts;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class ZigConfigurable extends MultiConfigurable {
|
||||||
|
public ZigConfigurable(@NotNull Project project) {
|
||||||
|
super(new ZigProjectConfigurable(project), new ZLSSettingsConfigurable(project));
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public @NlsContexts.ConfigurableName String getDisplayName() {
|
||||||
|
return "Zig";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* 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.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.settings.ZLSProjectSettingsService;
|
||||||
|
import com.intellij.facet.ui.ValidationResult;
|
||||||
|
import com.intellij.ide.util.projectWizard.AbstractNewProjectStep;
|
||||||
|
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.project.Project;
|
||||||
|
import com.intellij.openapi.util.NlsContexts;
|
||||||
|
import com.intellij.openapi.vfs.VfsUtil;
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
|
import com.intellij.openapi.wm.impl.welcomeScreen.AbstractActionWithPanel;
|
||||||
|
import com.intellij.platform.DirectoryProjectGenerator;
|
||||||
|
import com.intellij.platform.ProjectGeneratorPeer;
|
||||||
|
import com.intellij.util.ResourceUtil;
|
||||||
|
import lombok.val;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import javax.swing.Icon;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class ZigDirectoryProjectGenerator implements DirectoryProjectGenerator<ZigProjectConfigurationData>,
|
||||||
|
CustomStepProjectGenerator<ZigProjectConfigurationData> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull @NlsContexts.Label String getName() {
|
||||||
|
return "Zig";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Icon getLogo() {
|
||||||
|
return Icons.ZIG;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ProjectGeneratorPeer<ZigProjectConfigurationData> createPeer() {
|
||||||
|
return new ZigProjectGeneratorPeer(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ValidationResult validate(@NotNull String baseDirPath) {
|
||||||
|
return ValidationResult.OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void generateProject(@NotNull Project project, @NotNull VirtualFile baseDir, @NotNull ZigProjectConfigurationData data, @NotNull Module module) {
|
||||||
|
data.generateProject(this, project, baseDir, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractActionWithPanel createStep(DirectoryProjectGenerator<ZigProjectConfigurationData> projectGenerator, AbstractNewProjectStep.AbstractCallback<ZigProjectConfigurationData> callback) {
|
||||||
|
return new ZigProjectSettingsStep(projectGenerator);
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,24 +14,29 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.project.ide.util.projectwizard;
|
package com.falsepattern.zigbrains.project.ide.newproject;
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.ide.newproject.ZigProjectConfigurationData;
|
|
||||||
import com.falsepattern.zigbrains.project.openapi.module.ZigModuleType;
|
import com.falsepattern.zigbrains.project.openapi.module.ZigModuleType;
|
||||||
|
import com.falsepattern.zigbrains.project.util.ExperimentUtil;
|
||||||
import com.intellij.ide.NewProjectWizardLegacy;
|
import com.intellij.ide.NewProjectWizardLegacy;
|
||||||
import com.intellij.ide.util.projectWizard.ModuleBuilder;
|
import com.intellij.ide.util.projectWizard.ModuleBuilder;
|
||||||
import com.intellij.ide.util.projectWizard.ModuleWizardStep;
|
import com.intellij.ide.util.projectWizard.ModuleWizardStep;
|
||||||
import com.intellij.ide.util.projectWizard.WizardContext;
|
import com.intellij.ide.util.projectWizard.WizardContext;
|
||||||
|
import com.intellij.ide.wizard.CommitStepException;
|
||||||
import com.intellij.openapi.Disposable;
|
import com.intellij.openapi.Disposable;
|
||||||
import com.intellij.openapi.module.ModuleType;
|
import com.intellij.openapi.module.ModuleType;
|
||||||
import com.intellij.openapi.roots.ModifiableRootModel;
|
import com.intellij.openapi.roots.ModifiableRootModel;
|
||||||
import com.intellij.openapi.util.Disposer;
|
import com.intellij.openapi.util.Disposer;
|
||||||
|
import com.intellij.util.ui.JBUI;
|
||||||
import lombok.val;
|
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.JComponent;
|
||||||
|
|
||||||
public class ZigModuleBuilder extends ModuleBuilder {
|
public class ZigModuleBuilder extends ModuleBuilder {
|
||||||
public @Nullable ZigProjectConfigurationData configurationData = null;
|
public @Nullable ZigProjectConfigurationData configurationData = null;
|
||||||
|
public boolean forceGitignore = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModuleType<?> getModuleType() {
|
public ModuleType<?> getModuleType() {
|
||||||
|
@ -45,7 +50,7 @@ public class ZigModuleBuilder extends ModuleBuilder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setupRootModel(@NotNull ModifiableRootModel modifiableRootModel) {
|
public void setupRootModel(@NotNull ModifiableRootModel modifiableRootModel) {
|
||||||
createProject(modifiableRootModel, "git");
|
createProject(modifiableRootModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -55,8 +60,8 @@ public class ZigModuleBuilder extends ModuleBuilder {
|
||||||
return step;
|
return step;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createProject(ModifiableRootModel modifiableRootModel, @Nullable String vcs) {
|
public void createProject(ModifiableRootModel rootModel) {
|
||||||
val contentEntry = doAddContentEntry(modifiableRootModel);
|
val contentEntry = doAddContentEntry(rootModel);
|
||||||
if (contentEntry == null) {
|
if (contentEntry == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -64,7 +69,36 @@ public class ZigModuleBuilder extends ModuleBuilder {
|
||||||
if (root == null) {
|
if (root == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
modifiableRootModel.inheritSdk();
|
if (configurationData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
configurationData.generateProject(this, rootModel.getProject(), root, forceGitignore);
|
||||||
root.refresh(false, true);
|
root.refresh(false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ZigModuleWizardStep extends ModuleWizardStep {
|
||||||
|
private final ZigProjectGeneratorPeer peer = new ZigProjectGeneratorPeer(true);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JComponent getComponent() {
|
||||||
|
return withBorderIfNeeded(peer.getComponent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disposeUIResources() {
|
||||||
|
peer.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateDataModel() {
|
||||||
|
ZigModuleBuilder.this.configurationData = peer.getSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends JComponent> T withBorderIfNeeded(T component) {
|
||||||
|
if (ExperimentUtil.isNewWizard()) {
|
||||||
|
component.setBorder(JBUI.Borders.empty(14, 20));
|
||||||
|
}
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -16,19 +16,23 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.project.ide.newproject;
|
package com.falsepattern.zigbrains.project.ide.newproject;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.common.util.dsl.JavaPanel;
|
||||||
import com.falsepattern.zigbrains.project.ide.project.ZigDefaultTemplate;
|
import com.falsepattern.zigbrains.project.ide.project.ZigDefaultTemplate;
|
||||||
import com.falsepattern.zigbrains.project.ide.project.ZigProjectSettingsPanel;
|
import com.falsepattern.zigbrains.project.ide.project.ZigProjectSettingsPanel;
|
||||||
import com.falsepattern.zigbrains.project.ide.project.ZigProjectTemplate;
|
import com.falsepattern.zigbrains.project.ide.project.ZigProjectTemplate;
|
||||||
|
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.openapi.util.Disposer;
|
|
||||||
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.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.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;
|
||||||
|
@ -40,11 +44,20 @@ import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public class ZigNewProjectPanel implements Disposable {
|
public class ZigNewProjectPanel implements Disposable {
|
||||||
private final ZigProjectSettingsPanel projectSettingsPanel = new ZigProjectSettingsPanel();
|
private boolean handleGit;
|
||||||
|
private JBCheckBox git = new JBCheckBox();
|
||||||
|
private ZigProjectSettingsPanel projConf;
|
||||||
|
private ZLSSettingsPanel zlsConf;
|
||||||
|
|
||||||
|
public ZigNewProjectPanel(boolean handleGit) {
|
||||||
|
this.handleGit = handleGit;
|
||||||
|
projConf = new ZigProjectSettingsPanel();
|
||||||
|
zlsConf = new ZLSSettingsPanel();
|
||||||
|
}
|
||||||
|
|
||||||
public ZigProjectConfigurationData getData() {
|
public ZigProjectConfigurationData getData() {
|
||||||
ZigProjectTemplate selectedTemplate = templateList.getSelectedValue();
|
ZigProjectTemplate selectedTemplate = templateList.getSelectedValue();
|
||||||
return new ZigProjectConfigurationData(projectSettingsPanel.getData(), selectedTemplate);
|
return new ZigProjectConfigurationData(handleGit && git.isSelected(), projConf.getData(), zlsConf.getData(), selectedTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final List<ZigProjectTemplate> defaultTemplates = Arrays.asList(
|
private final List<ZigProjectTemplate> defaultTemplates = Arrays.asList(
|
||||||
|
@ -75,23 +88,29 @@ public class ZigNewProjectPanel implements Disposable {
|
||||||
.disableAddAction()
|
.disableAddAction()
|
||||||
.disableRemoveAction();
|
.disableRemoveAction();
|
||||||
|
|
||||||
public void attachPanelTo(Panel panel) {
|
public void attachPanelTo(JavaPanel p) {
|
||||||
projectSettingsPanel.attachPanelTo(panel);
|
if (handleGit) {
|
||||||
|
p.row("Create Git repository", r -> r.cell(git));
|
||||||
panel.groupRowsRange("Zig Project Template", false, null, null, (p) -> {
|
}
|
||||||
p.row((JLabel) null, (r) -> {
|
p.group("Zig Project Template", true, (p2) -> {
|
||||||
|
p2.row((r) -> {
|
||||||
r.resizableRow();
|
r.resizableRow();
|
||||||
r.cell(templateToolbar.createPanel())
|
r.cell(templateToolbar.createPanel())
|
||||||
.align(AlignX.FILL)
|
.align(AlignX.FILL)
|
||||||
.align(AlignY.FILL);
|
.align(AlignY.FILL);
|
||||||
return null;
|
|
||||||
});
|
});
|
||||||
return null;
|
|
||||||
});
|
});
|
||||||
|
projConf.attachPanelTo(p);
|
||||||
|
zlsConf.attachPanelTo(p);
|
||||||
|
projConf.autodetect();
|
||||||
|
zlsConf.autodetect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
Disposer.dispose(projectSettingsPanel);
|
projConf.dispose();
|
||||||
|
zlsConf.dispose();
|
||||||
|
projConf = null;
|
||||||
|
zlsConf = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,26 +16,20 @@
|
||||||
|
|
||||||
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.common.util.FileUtil;
|
||||||
import com.falsepattern.zigbrains.project.ide.util.projectwizard.ZigModuleBuilder;
|
|
||||||
import com.falsepattern.zigbrains.project.platform.ZigProjectGeneratorPeer;
|
|
||||||
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.LanguageNewProjectWizard;
|
import com.intellij.ide.wizard.LanguageNewProjectWizard;
|
||||||
import com.intellij.ide.wizard.NewProjectWizardLanguageStep;
|
import com.intellij.ide.wizard.NewProjectWizardLanguageStep;
|
||||||
import com.intellij.ide.wizard.NewProjectWizardStep;
|
import com.intellij.ide.wizard.NewProjectWizardStep;
|
||||||
import com.intellij.openapi.module.Module;
|
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.openapi.roots.ModuleRootModificationUtil;
|
import com.intellij.openapi.roots.ModuleRootModificationUtil;
|
||||||
import com.intellij.openapi.vfs.VfsUtil;
|
|
||||||
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;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
public class ZigNewProjectWizard implements LanguageNewProjectWizard {
|
public class ZigNewProjectWizard implements LanguageNewProjectWizard {
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@ -56,7 +50,7 @@ public class ZigNewProjectWizard implements LanguageNewProjectWizard {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ZigNewProjectWizardStep extends AbstractNewProjectWizardStep {
|
private static class ZigNewProjectWizardStep extends AbstractNewProjectWizardStep {
|
||||||
private final ZigProjectGeneratorPeer peer = new ZigProjectGeneratorPeer();
|
private final ZigProjectGeneratorPeer peer = new ZigProjectGeneratorPeer(false);
|
||||||
|
|
||||||
public ZigNewProjectWizardStep(@NotNull NewProjectWizardStep parentStep) {
|
public ZigNewProjectWizardStep(@NotNull NewProjectWizardStep parentStep) {
|
||||||
super(parentStep);
|
super(parentStep);
|
||||||
|
@ -74,42 +68,10 @@ public class ZigNewProjectWizard implements LanguageNewProjectWizard {
|
||||||
@Override
|
@Override
|
||||||
public void setupProject(@NotNull Project project) {
|
public void setupProject(@NotNull Project project) {
|
||||||
val builder = new ZigModuleBuilder();
|
val builder = new ZigModuleBuilder();
|
||||||
val modList = builder.commit(project);
|
|
||||||
if (modList == null || modList.size() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
val module = modList.get(0);
|
|
||||||
|
|
||||||
//noinspection UsagesOfObsoleteApi
|
|
||||||
ModuleRootModificationUtil.updateModel(module, rootModel -> {
|
|
||||||
builder.configurationData = peer.getSettings();
|
builder.configurationData = peer.getSettings();
|
||||||
builder.createProject(rootModel, "none");
|
|
||||||
var gitData = GitNewProjectWizardData.Companion.getGitData(this);
|
var gitData = GitNewProjectWizardData.Companion.getGitData(this);
|
||||||
if (gitData == null) {
|
builder.forceGitignore = gitData != null && gitData.getGit();
|
||||||
return;
|
builder.commit(project);
|
||||||
}
|
|
||||||
if (gitData.getGit()) {
|
|
||||||
ApplicationUtil.writeAction(() -> createGitIgnoreFile(getContext().getProjectDirectory(), module));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String GITIGNORE = ".gitignore";
|
|
||||||
|
|
||||||
private static void createGitIgnoreFile(Path projectDir, Module module) {
|
|
||||||
try {
|
|
||||||
val directory = VfsUtil.createDirectoryIfMissing(projectDir.toString());
|
|
||||||
if (directory == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
val existingFile = directory.findChild(GITIGNORE);
|
|
||||||
if (existingFile != null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
directory.createChildData(module, GITIGNORE);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,132 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.project.ide.newproject;
|
package com.falsepattern.zigbrains.project.ide.newproject;
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.ide.project.ZigProjectSettingsPanel;
|
import com.falsepattern.zigbrains.common.util.ApplicationUtil;
|
||||||
|
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.ZigProjectSettingsService;
|
||||||
|
import com.falsepattern.zigbrains.zig.settings.ZLSProjectSettingsService;
|
||||||
|
import com.falsepattern.zigbrains.zig.settings.ZLSSettings;
|
||||||
|
import com.intellij.ide.wizard.GitNewProjectWizardData;
|
||||||
|
import com.intellij.notification.Notification;
|
||||||
|
import com.intellij.notification.NotificationType;
|
||||||
|
import com.intellij.notification.Notifications;
|
||||||
|
import com.intellij.openapi.GitRepositoryInitializer;
|
||||||
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
|
import com.intellij.openapi.application.WriteAction;
|
||||||
|
import com.intellij.openapi.module.Module;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.intellij.openapi.vfs.VfsUtil;
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
|
import com.intellij.util.ResourceUtil;
|
||||||
|
import lombok.Cleanup;
|
||||||
|
import lombok.val;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public record ZigProjectConfigurationData(ZigProjectSettingsPanel.SettingsData settings, ZigProjectTemplate selectedTemplate) {
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public record ZigProjectConfigurationData(boolean git, ZigProjectSettings projConf, ZLSSettings zlsConf, ZigProjectTemplate selectedTemplate) {
|
||||||
|
|
||||||
|
private static String getResourceString(String path) throws IOException {
|
||||||
|
byte[] data = ResourceUtil.getResourceAsBytes(path, ZigDirectoryProjectGenerator.class.getClassLoader());
|
||||||
|
if (data == null)
|
||||||
|
throw new IOException("Could not find resource " + path + "!");
|
||||||
|
return new String(data, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generateProject(@NotNull Object requestor, @NotNull Project project, @NotNull VirtualFile baseDir, boolean forceGitignore) {
|
||||||
|
val svc = ZigProjectSettingsService.getInstance(project);
|
||||||
|
svc.loadState(this.projConf());
|
||||||
|
ZLSProjectSettingsService.getInstance(project).loadState(this.zlsConf());
|
||||||
|
|
||||||
|
val toolchain = svc.getState().getToolchain();
|
||||||
|
|
||||||
|
val template = this.selectedTemplate();
|
||||||
|
|
||||||
|
if (template instanceof ZigDefaultTemplate.ZigInitTemplate) {
|
||||||
|
if (toolchain == null) {
|
||||||
|
Notifications.Bus.notify(new Notification("ZigBrains.Project",
|
||||||
|
"Tried to generate project with zig init, but zig toolchain is invalid!",
|
||||||
|
NotificationType.ERROR));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
val zig = toolchain.zig();
|
||||||
|
val resultOpt = zig.callWithArgs(baseDir.toNioPath(), 10000, "init");
|
||||||
|
if (resultOpt.isEmpty()) {
|
||||||
|
Notifications.Bus.notify(new Notification("ZigBrains.Project",
|
||||||
|
"Failed to invoke \"zig init\"!",
|
||||||
|
NotificationType.ERROR));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
val result = resultOpt.get();
|
||||||
|
if (result.getExitCode() != 0) {
|
||||||
|
Notifications.Bus.notify(new Notification("ZigBrains.Project",
|
||||||
|
"\"zig init\" failed with exit code " + result.getExitCode() + "! Check the IDE log files!",
|
||||||
|
NotificationType.ERROR));
|
||||||
|
System.err.println(result.getStderr());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
val projectName = project.getName();
|
||||||
|
WriteAction.run(() -> {
|
||||||
|
for (val fileTemplate : template.fileTemplates().entrySet()) {
|
||||||
|
var fileName = fileTemplate.getKey();
|
||||||
|
VirtualFile parentDir;
|
||||||
|
if (fileName.contains("/")) {
|
||||||
|
val slashIndex = fileName.indexOf('/');
|
||||||
|
parentDir = baseDir.createChildDirectory(requestor, fileName.substring(0, slashIndex));
|
||||||
|
fileName = fileName.substring(slashIndex + 1);
|
||||||
|
} else {
|
||||||
|
parentDir = baseDir;
|
||||||
|
}
|
||||||
|
val templateDir = fileTemplate.getValue();
|
||||||
|
val resourceData = getResourceString("project-gen/" + templateDir + "/" + fileName + ".template").replace("@@PROJECT_NAME@@", projectName);
|
||||||
|
val targetFile = parentDir.createChildData(requestor, fileName);
|
||||||
|
VfsUtil.saveText(targetFile, resourceData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (git) {
|
||||||
|
ApplicationManager.getApplication().executeOnPooledThread(() -> {
|
||||||
|
val initializer = GitRepositoryInitializer.getInstance();
|
||||||
|
if (initializer != null) {
|
||||||
|
initializer.initRepository(project, baseDir);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (git || forceGitignore) {
|
||||||
|
createGitIgnoreFile(baseDir, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static final String GITIGNORE = ".gitignore";
|
||||||
|
|
||||||
|
private static void createGitIgnoreFile(VirtualFile projectDir, Object requestor) {
|
||||||
|
val existingFile = projectDir.findChild(GITIGNORE);
|
||||||
|
if (existingFile != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WriteAction.run(() -> {
|
||||||
|
VirtualFile file = null;
|
||||||
|
try {
|
||||||
|
file = projectDir.createChildData(requestor, GITIGNORE);
|
||||||
|
@Cleanup val res = ZigProjectConfigurationData.class.getResourceAsStream("/fileTemplates/internal/gitignore");
|
||||||
|
if (res == null)
|
||||||
|
return;
|
||||||
|
file.setCharset(StandardCharsets.UTF_8);
|
||||||
|
file.setBinaryContent(res.readAllBytes());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,19 +14,22 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.project.platform;
|
package com.falsepattern.zigbrains.project.ide.newproject;
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.ide.newproject.ZigNewProjectPanel;
|
import com.intellij.openapi.util.Disposer;
|
||||||
import com.falsepattern.zigbrains.project.ide.newproject.ZigProjectConfigurationData;
|
|
||||||
import com.intellij.platform.GeneratorPeerImpl;
|
import com.intellij.platform.GeneratorPeerImpl;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
|
|
||||||
import static com.intellij.ui.dsl.builder.BuilderKt.panel;
|
import static com.falsepattern.zigbrains.common.util.dsl.JavaPanel.newPanel;
|
||||||
|
|
||||||
public class ZigProjectGeneratorPeer extends GeneratorPeerImpl<ZigProjectConfigurationData> {
|
public class ZigProjectGeneratorPeer extends GeneratorPeerImpl<ZigProjectConfigurationData> {
|
||||||
private final ZigNewProjectPanel newProjectPanel = new ZigNewProjectPanel();
|
private final ZigNewProjectPanel newProjectPanel;
|
||||||
|
|
||||||
|
public ZigProjectGeneratorPeer(boolean handleGit) {
|
||||||
|
newProjectPanel = new ZigNewProjectPanel(handleGit);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull ZigProjectConfigurationData getSettings() {
|
public @NotNull ZigProjectConfigurationData getSettings() {
|
||||||
|
@ -35,9 +38,10 @@ public class ZigProjectGeneratorPeer extends GeneratorPeerImpl<ZigProjectConfigu
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull JComponent getComponent() {
|
public @NotNull JComponent getComponent() {
|
||||||
return panel((p) -> {
|
return newPanel(newProjectPanel::attachPanelTo);
|
||||||
newProjectPanel.attachPanelTo(p);
|
}
|
||||||
return null;
|
|
||||||
});
|
public void dispose() {
|
||||||
|
Disposer.dispose(newProjectPanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.project.ide.util.projectwizard;
|
package com.falsepattern.zigbrains.project.ide.newproject;
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.ide.newproject.ZigProjectConfigurationData;
|
import com.falsepattern.zigbrains.project.ide.newproject.ZigProjectConfigurationData;
|
||||||
import com.intellij.ide.util.projectWizard.AbstractNewProjectStep;
|
import com.intellij.ide.util.projectWizard.AbstractNewProjectStep;
|
|
@ -16,23 +16,17 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.project.ide.project;
|
package com.falsepattern.zigbrains.project.ide.project;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.common.SubConfigurable;
|
||||||
|
import com.falsepattern.zigbrains.common.util.dsl.JavaPanel;
|
||||||
import com.falsepattern.zigbrains.project.openapi.components.ZigProjectSettingsService;
|
import com.falsepattern.zigbrains.project.openapi.components.ZigProjectSettingsService;
|
||||||
import com.falsepattern.zigbrains.zig.lsp.ZLSStartupActivity;
|
import com.falsepattern.zigbrains.zig.lsp.ZLSStartupActivity;
|
||||||
import com.intellij.openapi.options.Configurable;
|
|
||||||
import com.intellij.openapi.options.ConfigurationException;
|
import com.intellij.openapi.options.ConfigurationException;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.openapi.util.Disposer;
|
import com.intellij.openapi.util.Disposer;
|
||||||
import com.intellij.openapi.util.NlsContexts;
|
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import javax.swing.JComponent;
|
public class ZigProjectConfigurable implements SubConfigurable {
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import static com.intellij.ui.dsl.builder.BuilderKt.panel;
|
|
||||||
|
|
||||||
public class ZigProjectConfigurable implements Configurable {
|
|
||||||
private ZigProjectSettingsPanel settingsPanel;
|
private ZigProjectSettingsPanel settingsPanel;
|
||||||
|
|
||||||
private final Project project;
|
private final Project project;
|
||||||
|
@ -42,36 +36,22 @@ public class ZigProjectConfigurable implements Configurable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NlsContexts.ConfigurableName String getDisplayName() {
|
public void createComponent(JavaPanel panel) {
|
||||||
return "Zig";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable JComponent createComponent() {
|
|
||||||
settingsPanel = new ZigProjectSettingsPanel();
|
settingsPanel = new ZigProjectSettingsPanel();
|
||||||
return panel((p) -> {
|
settingsPanel.attachPanelTo(panel);
|
||||||
settingsPanel.attachPanelTo(p);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isModified() {
|
public boolean isModified() {
|
||||||
var zigSettings = ZigProjectSettingsService.getInstance(project);
|
return ZigProjectSettingsService.getInstance(project).isModified(settingsPanel.getData());
|
||||||
var settingsData = settingsPanel.getData();
|
|
||||||
return !Objects.equals(settingsData.toolchain(), zigSettings.getToolchain()) ||
|
|
||||||
!Objects.equals(settingsData.explicitPathToStd(), zigSettings.getExplicitPathToStd());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void apply() throws ConfigurationException {
|
public void apply() throws ConfigurationException {
|
||||||
val zigSettings = ZigProjectSettingsService.getInstance(project);
|
val service = ZigProjectSettingsService.getInstance(project);
|
||||||
val settingsData = settingsPanel.getData();
|
val data = settingsPanel.getData();
|
||||||
boolean modified = isModified();
|
val modified = service.isModified(data);
|
||||||
zigSettings.modify((settings) -> {
|
service.loadState(data);
|
||||||
settings.setToolchain(settingsData.toolchain());
|
|
||||||
settings.setExplicitPathToStd(settingsData.explicitPathToStd());
|
|
||||||
});
|
|
||||||
if (modified) {
|
if (modified) {
|
||||||
ZLSStartupActivity.initZLS(project);
|
ZLSStartupActivity.initZLS(project);
|
||||||
}
|
}
|
||||||
|
@ -80,10 +60,7 @@ public class ZigProjectConfigurable implements Configurable {
|
||||||
@Override
|
@Override
|
||||||
public void reset() {
|
public void reset() {
|
||||||
val zigSettings = ZigProjectSettingsService.getInstance(project);
|
val zigSettings = ZigProjectSettingsService.getInstance(project);
|
||||||
settingsPanel.setData(new ZigProjectSettingsPanel.SettingsData(
|
settingsPanel.setData(zigSettings.getState());
|
||||||
zigSettings.getExplicitPathToStd(),
|
|
||||||
zigSettings.getToolchain()
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -16,10 +16,13 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.project.ide.project;
|
package com.falsepattern.zigbrains.project.ide.project;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.common.util.PathUtil;
|
||||||
import com.falsepattern.zigbrains.common.util.StringUtil;
|
import com.falsepattern.zigbrains.common.util.StringUtil;
|
||||||
import com.falsepattern.zigbrains.common.util.TextFieldUtil;
|
import com.falsepattern.zigbrains.common.util.TextFieldUtil;
|
||||||
|
import com.falsepattern.zigbrains.common.util.dsl.JavaPanel;
|
||||||
import com.falsepattern.zigbrains.project.openapi.MyDisposable;
|
import com.falsepattern.zigbrains.project.openapi.MyDisposable;
|
||||||
import com.falsepattern.zigbrains.project.openapi.UIDebouncer;
|
import com.falsepattern.zigbrains.project.openapi.UIDebouncer;
|
||||||
|
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.project.toolchain.AbstractZigToolchain;
|
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
|
||||||
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainProvider;
|
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainProvider;
|
||||||
|
@ -29,26 +32,25 @@ import com.intellij.openapi.util.Disposer;
|
||||||
import com.intellij.openapi.util.Pair;
|
import com.intellij.openapi.util.Pair;
|
||||||
import com.intellij.ui.JBColor;
|
import com.intellij.ui.JBColor;
|
||||||
import com.intellij.ui.dsl.builder.AlignX;
|
import com.intellij.ui.dsl.builder.AlignX;
|
||||||
import com.intellij.ui.dsl.builder.Panel;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static com.falsepattern.zigbrains.common.util.KtUtil.$f;
|
||||||
|
|
||||||
public class ZigProjectSettingsPanel implements MyDisposable {
|
public class ZigProjectSettingsPanel implements MyDisposable {
|
||||||
@Getter
|
@Getter
|
||||||
private boolean disposed = false;
|
private boolean disposed = false;
|
||||||
|
|
||||||
public record SettingsData(@Nullable String explicitPathToStd,
|
|
||||||
@Nullable AbstractZigToolchain toolchain) {}
|
|
||||||
|
|
||||||
private final UIDebouncer versionUpdateDebouncer = new UIDebouncer(this);
|
private final UIDebouncer versionUpdateDebouncer = new UIDebouncer(this);
|
||||||
|
|
||||||
private final ZigToolchainPathChooserComboBox toolchainPathChooserComboBox = new ZigToolchainPathChooserComboBox(this::updateUI);
|
private final TextFieldWithBrowseButton pathToToolchain = TextFieldUtil.pathToDirectoryTextField(this,
|
||||||
|
"Path to the Zig Toolchain",
|
||||||
|
this::updateUI);
|
||||||
|
|
||||||
private final JLabel toolchainVersion = new JLabel();
|
private final JLabel toolchainVersion = new JLabel();
|
||||||
|
|
||||||
|
@ -56,56 +58,57 @@ public class ZigProjectSettingsPanel implements MyDisposable {
|
||||||
"Path to Standard Library",
|
"Path to Standard Library",
|
||||||
() -> {});
|
() -> {});
|
||||||
|
|
||||||
public SettingsData getData() {
|
private void autodetect(ActionEvent e) {
|
||||||
val toolchain = Optional.ofNullable(toolchainPathChooserComboBox.getSelectedPath())
|
autodetect();
|
||||||
.map(ZigToolchainProvider::findToolchain)
|
|
||||||
.orElse(null);
|
|
||||||
return new SettingsData(StringUtil.blankToNull(pathToStdField.getText()), toolchain);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setData(SettingsData value) {
|
public void autodetect() {
|
||||||
toolchainPathChooserComboBox.setSelectedPath(Optional.ofNullable(value.toolchain()).map(tc -> tc.location).orElse(null));
|
val tc = AbstractZigToolchain.suggest();
|
||||||
|
if (tc != null) {
|
||||||
|
pathToToolchain.setText(PathUtil.stringFromPath(tc.getLocation()));
|
||||||
|
updateUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pathToStdField.setText(Optional.ofNullable(value.explicitPathToStd()).orElse(""));
|
public ZigProjectSettings getData() {
|
||||||
|
val toolchain = Optional.of(pathToToolchain.getText())
|
||||||
|
.map(PathUtil::pathFromString)
|
||||||
|
.map(ZigToolchainProvider::findToolchain)
|
||||||
|
.orElse(null);
|
||||||
|
return new ZigProjectSettings(StringUtil.blankToNull(pathToStdField.getText()), toolchain);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(ZigProjectSettings value) {
|
||||||
|
pathToToolchain.setText(Optional.ofNullable(value.getToolchainHomeDirectory())
|
||||||
|
.orElse(""));
|
||||||
|
|
||||||
|
pathToStdField.setText(Optional.ofNullable(value.getExplicitPathToStd()).orElse(""));
|
||||||
|
|
||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void attachPanelTo(Panel panel) {
|
public void attachPanelTo(JavaPanel p) {
|
||||||
setData(new SettingsData(null,
|
Optional.ofNullable(ZigProjectSettingsService.getInstance(ProjectManager.getInstance().getDefaultProject()))
|
||||||
Optional.ofNullable(ProjectManager.getInstance()
|
.map(ZigProjectSettingsService::getState)
|
||||||
.getDefaultProject()
|
.ifPresent(this::setData);
|
||||||
.getService(ZigProjectSettingsService.class))
|
p.group("Zig Settings", true, p2 -> {
|
||||||
.map(ZigProjectSettingsService::getToolchain)
|
p2.row("Toolchain location", r -> {
|
||||||
.orElse(AbstractZigToolchain.suggest(Paths.get(".")))));
|
r.cell(pathToToolchain).resizableColumn().align(AlignX.FILL);
|
||||||
|
r.button("Autodetect", $f(this::autodetect));
|
||||||
panel.row("Toolchain Location", (r) -> {
|
|
||||||
r.cell(toolchainPathChooserComboBox)
|
|
||||||
.align(AlignX.FILL);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
});
|
});
|
||||||
|
p2.cell("Toolchain version", toolchainVersion);
|
||||||
panel.row("Toolchain Version", (r) -> {
|
p2.cell("Standard library location", pathToStdField, AlignX.FILL);
|
||||||
r.cell(toolchainVersion);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
panel.row("Standard Library Location", (r) -> {
|
|
||||||
r.cell(pathToStdField)
|
|
||||||
.align(AlignX.FILL);
|
|
||||||
return null;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
disposed = true;
|
disposed = true;
|
||||||
Disposer.dispose(toolchainPathChooserComboBox);
|
Disposer.dispose(pathToToolchain);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateUI() {
|
private void updateUI() {
|
||||||
val pathToToolchain = toolchainPathChooserComboBox.getSelectedPath();
|
val pathToToolchain = PathUtil.pathFromString(this.pathToToolchain.getText());
|
||||||
|
|
||||||
versionUpdateDebouncer.run(
|
versionUpdateDebouncer.run(
|
||||||
() -> {
|
() -> {
|
||||||
|
|
|
@ -1,78 +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.project.ide.project;
|
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.common.util.TextFieldUtil;
|
|
||||||
import com.intellij.openapi.fileChooser.FileChooser;
|
|
||||||
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
|
|
||||||
import com.intellij.openapi.ui.ComboBoxWithWidePopup;
|
|
||||||
import com.intellij.openapi.ui.ComponentWithBrowseButton;
|
|
||||||
import com.intellij.ui.AnimatedIcon;
|
|
||||||
import com.intellij.ui.ComboboxSpeedSearch;
|
|
||||||
import com.intellij.ui.components.fields.ExtendableTextComponent;
|
|
||||||
import com.intellij.ui.components.fields.ExtendableTextField;
|
|
||||||
import lombok.val;
|
|
||||||
|
|
||||||
import javax.swing.JTextField;
|
|
||||||
import javax.swing.plaf.basic.BasicComboBoxEditor;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
public class ZigToolchainPathChooserComboBox extends ComponentWithBrowseButton<ComboBoxWithWidePopup<Path>> {
|
|
||||||
public Runnable onTextChanged;
|
|
||||||
|
|
||||||
private final BasicComboBoxEditor comboBoxEditor = new BasicComboBoxEditor() {
|
|
||||||
@Override
|
|
||||||
protected JTextField createEditorComponent() {
|
|
||||||
return new ExtendableTextField();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private ExtendableTextField getPathTextField() {
|
|
||||||
return (ExtendableTextField) getChildComponent().getEditor().getEditorComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private final ExtendableTextComponent.Extension busyIconExtension = hovered -> AnimatedIcon.Default.INSTANCE;
|
|
||||||
|
|
||||||
public Path getSelectedPath() {
|
|
||||||
return Path.of(getPathTextField().getText());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSelectedPath(Path path) {
|
|
||||||
if (path == null) {
|
|
||||||
getPathTextField().setText("");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
getPathTextField().setText(path.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public ZigToolchainPathChooserComboBox(Runnable onTextChanged) {
|
|
||||||
super(new ComboBoxWithWidePopup<>(), null);
|
|
||||||
this.onTextChanged = onTextChanged;
|
|
||||||
|
|
||||||
new ComboboxSpeedSearch(getChildComponent());
|
|
||||||
getChildComponent().setEditor(comboBoxEditor);
|
|
||||||
getChildComponent().setEditable(true);
|
|
||||||
|
|
||||||
addActionListener(e -> {
|
|
||||||
val descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
|
|
||||||
//noinspection UsagesOfObsoleteApi
|
|
||||||
FileChooser.chooseFile(descriptor, null, null, (file) -> getChildComponent().setSelectedItem(file.toNioPath()));
|
|
||||||
});
|
|
||||||
|
|
||||||
TextFieldUtil.addTextChangeListener(getPathTextField(), ignored -> onTextChanged.run());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,56 +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.project.ide.util.projectwizard;
|
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.ide.newproject.ZigNewProjectPanel;
|
|
||||||
import com.falsepattern.zigbrains.project.util.ExperimentUtil;
|
|
||||||
import com.intellij.ide.util.projectWizard.ModuleWizardStep;
|
|
||||||
import com.intellij.openapi.util.Disposer;
|
|
||||||
import com.intellij.util.ui.JBUI;
|
|
||||||
|
|
||||||
import javax.swing.JComponent;
|
|
||||||
|
|
||||||
import static com.intellij.ui.dsl.builder.BuilderKt.panel;
|
|
||||||
|
|
||||||
public class ZigModuleWizardStep extends ModuleWizardStep {
|
|
||||||
private final ZigNewProjectPanel newProjectPanel = new ZigNewProjectPanel();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JComponent getComponent() {
|
|
||||||
return withBorderIfNeeded(panel((p) -> {
|
|
||||||
newProjectPanel.attachPanelTo(p);
|
|
||||||
return null;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void disposeUIResources() {
|
|
||||||
Disposer.dispose(newProjectPanel);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateDataModel() {
|
|
||||||
throw new UnsupportedOperationException("Not yet implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T extends JComponent> T withBorderIfNeeded(T component) {
|
|
||||||
if (ExperimentUtil.isNewWizard()) {
|
|
||||||
component.setBorder(JBUI.Borders.empty(14, 20));
|
|
||||||
}
|
|
||||||
return component;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -16,26 +16,16 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.project.openapi.components;
|
package com.falsepattern.zigbrains.project.openapi.components;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.common.WrappingStateComponent;
|
||||||
import com.intellij.openapi.components.PersistentStateComponent;
|
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 com.intellij.util.xmlb.XmlSerializerUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public abstract class AbstractZigProjectSettingsService<T> implements PersistentStateComponent<T> {
|
public abstract class AbstractZigProjectSettingsService<T> extends WrappingStateComponent<T> {
|
||||||
public final transient Project project;
|
public final transient Project project;
|
||||||
private final T state;
|
|
||||||
public AbstractZigProjectSettingsService(Project project, @NotNull T initialState) {
|
public AbstractZigProjectSettingsService(Project project, @NotNull T initialState) {
|
||||||
|
super(initialState);
|
||||||
this.project = project;
|
this.project = project;
|
||||||
this.state = initialState;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull T getState() {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void loadState(@NotNull T state) {
|
|
||||||
XmlSerializerUtil.copyBean(state, this.state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,20 +20,23 @@ import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
|
||||||
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainProvider;
|
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainProvider;
|
||||||
import com.intellij.util.io.PathKt;
|
import com.intellij.util.io.PathKt;
|
||||||
import com.intellij.util.xmlb.annotations.Transient;
|
import com.intellij.util.xmlb.annotations.Transient;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
public class ZigProjectSettings {
|
public class ZigProjectSettings {
|
||||||
public String toolchainHomeDirectory = null;
|
public String explicitPathToStd;
|
||||||
public String explicitPathToStd = null;
|
public String toolchainHomeDirectory;
|
||||||
|
|
||||||
public String getExplicitPathToStd() {
|
public ZigProjectSettings(String explicitPathToStd, AbstractZigToolchain toolchain) {
|
||||||
return explicitPathToStd;
|
this(explicitPathToStd, (String)null);
|
||||||
}
|
setToolchain(toolchain);
|
||||||
|
|
||||||
public void setExplicitPathToStd(String value) {
|
|
||||||
explicitPathToStd = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
|
@ -50,7 +53,7 @@ public class ZigProjectSettings {
|
||||||
toolchainHomeDirectory = null;
|
toolchainHomeDirectory = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var loc = value.location;
|
var loc = value.getLocation();
|
||||||
if (loc == null) {
|
if (loc == null) {
|
||||||
toolchainHomeDirectory = null;
|
toolchainHomeDirectory = null;
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -16,13 +16,17 @@
|
||||||
|
|
||||||
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.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 org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
@Service(Service.Level.PROJECT)
|
@Service(Service.Level.PROJECT)
|
||||||
|
@ -39,16 +43,9 @@ public final class ZigProjectSettingsService extends AbstractZigProjectSettingsS
|
||||||
return project.getService(ZigProjectSettingsService.class);
|
return project.getService(ZigProjectSettingsService.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable AbstractZigToolchain getToolchain() {
|
public boolean isModified(ZigProjectSettings otherData) {
|
||||||
return getState().getToolchain();
|
val myData = getState();
|
||||||
}
|
return !Objects.equals(myData.toolchainHomeDirectory, otherData.toolchainHomeDirectory) ||
|
||||||
|
!Objects.equals(myData.explicitPathToStd, otherData.explicitPathToStd);
|
||||||
public @Nullable String getExplicitPathToStd() {
|
|
||||||
return getState().getExplicitPathToStd();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void modify(Consumer<ZigProjectSettings> modifier) {
|
|
||||||
var state = getState();
|
|
||||||
modifier.accept(state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.project.openapi.module;
|
package com.falsepattern.zigbrains.project.openapi.module;
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.ide.util.projectwizard.ZigModuleBuilder;
|
import com.falsepattern.zigbrains.project.ide.newproject.ZigModuleBuilder;
|
||||||
import com.falsepattern.zigbrains.zig.Icons;
|
import com.falsepattern.zigbrains.zig.Icons;
|
||||||
import com.intellij.openapi.module.ModuleType;
|
import com.intellij.openapi.module.ModuleType;
|
||||||
import org.jetbrains.annotations.Nls;
|
import org.jetbrains.annotations.Nls;
|
||||||
|
|
|
@ -1,140 +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.project.platform;
|
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.ide.newproject.ZigProjectConfigurationData;
|
|
||||||
import com.falsepattern.zigbrains.project.ide.project.ZigDefaultTemplate;
|
|
||||||
import com.falsepattern.zigbrains.project.ide.util.projectwizard.ZigProjectSettingsStep;
|
|
||||||
import com.falsepattern.zigbrains.project.openapi.components.ZigProjectSettingsService;
|
|
||||||
import com.falsepattern.zigbrains.zig.Icons;
|
|
||||||
import com.intellij.facet.ui.ValidationResult;
|
|
||||||
import com.intellij.ide.util.projectWizard.AbstractNewProjectStep;
|
|
||||||
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.project.Project;
|
|
||||||
import com.intellij.openapi.util.NlsContexts;
|
|
||||||
import com.intellij.openapi.vfs.VfsUtil;
|
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
|
||||||
import com.intellij.openapi.wm.impl.welcomeScreen.AbstractActionWithPanel;
|
|
||||||
import com.intellij.platform.DirectoryProjectGenerator;
|
|
||||||
import com.intellij.platform.ProjectGeneratorPeer;
|
|
||||||
import com.intellij.util.ResourceUtil;
|
|
||||||
import lombok.val;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import javax.swing.Icon;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
public class ZigDirectoryProjectGenerator implements DirectoryProjectGenerator<ZigProjectConfigurationData>,
|
|
||||||
CustomStepProjectGenerator<ZigProjectConfigurationData> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull @NlsContexts.Label String getName() {
|
|
||||||
return "Zig";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable Icon getLogo() {
|
|
||||||
return Icons.ZIG;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull ProjectGeneratorPeer<ZigProjectConfigurationData> createPeer() {
|
|
||||||
return new ZigProjectGeneratorPeer();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull ValidationResult validate(@NotNull String baseDirPath) {
|
|
||||||
return ValidationResult.OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getResourceString(String path) throws IOException {
|
|
||||||
byte[] data = ResourceUtil.getResourceAsBytes(path, ZigDirectoryProjectGenerator.class.getClassLoader());
|
|
||||||
if (data == null)
|
|
||||||
throw new IOException("Could not find resource " + path + "!");
|
|
||||||
return new String(data, StandardCharsets.UTF_8);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void generateProject(@NotNull Project project, @NotNull VirtualFile baseDir, @NotNull ZigProjectConfigurationData data, @NotNull Module module) {
|
|
||||||
val settings = data.settings();
|
|
||||||
|
|
||||||
var svc = ZigProjectSettingsService.getInstance(project);
|
|
||||||
val toolchain = settings.toolchain();
|
|
||||||
svc.getState().setToolchain(toolchain);
|
|
||||||
|
|
||||||
val template = data.selectedTemplate();
|
|
||||||
|
|
||||||
if (template instanceof ZigDefaultTemplate.ZigInitTemplate) {
|
|
||||||
if (toolchain == null) {
|
|
||||||
Notifications.Bus.notify(new Notification("ZigBrains.Project",
|
|
||||||
"Tried to generate project with zig init, but zig toolchain is invalid!",
|
|
||||||
NotificationType.ERROR));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
val zig = toolchain.zig();
|
|
||||||
val resultOpt = zig.callWithArgs(baseDir.toNioPath(), 10000, "init");
|
|
||||||
if (resultOpt.isEmpty()) {
|
|
||||||
Notifications.Bus.notify(new Notification("ZigBrains.Project",
|
|
||||||
"Failed to invoke \"zig init\"!",
|
|
||||||
NotificationType.ERROR));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
val result = resultOpt.get();
|
|
||||||
if (result.getExitCode() != 0) {
|
|
||||||
Notifications.Bus.notify(new Notification("ZigBrains.Project",
|
|
||||||
"\"zig init\" failed with exit code " + result.getExitCode() + "! Check the IDE log files!",
|
|
||||||
NotificationType.ERROR));
|
|
||||||
System.err.println(result.getStderr());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
val projectName = project.getName();
|
|
||||||
WriteAction.run(() -> {
|
|
||||||
for (val fileTemplate : template.fileTemplates().entrySet()) {
|
|
||||||
var fileName = fileTemplate.getKey();
|
|
||||||
VirtualFile parentDir;
|
|
||||||
if (fileName.contains("/")) {
|
|
||||||
val slashIndex = fileName.indexOf('/');
|
|
||||||
parentDir = baseDir.createChildDirectory(this, fileName.substring(0, slashIndex));
|
|
||||||
fileName = fileName.substring(slashIndex + 1);
|
|
||||||
} else {
|
|
||||||
parentDir = baseDir;
|
|
||||||
}
|
|
||||||
val templateDir = fileTemplate.getValue();
|
|
||||||
val resourceData = getResourceString("project-gen/" + templateDir + "/" + fileName + ".template").replace("@@PROJECT_NAME@@", projectName);
|
|
||||||
val targetFile = parentDir.createChildData(this, fileName);
|
|
||||||
VfsUtil.saveText(targetFile, resourceData);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AbstractActionWithPanel createStep(DirectoryProjectGenerator<ZigProjectConfigurationData> projectGenerator, AbstractNewProjectStep.AbstractCallback<ZigProjectConfigurationData> callback) {
|
|
||||||
return new ZigProjectSettingsStep(projectGenerator);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -52,7 +52,7 @@ public abstract class ZigProgramRunnerBase<ProfileState extends ProfileStateBase
|
||||||
if (state == null)
|
if (state == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
val toolchain = ZigProjectSettingsService.getInstance(environment.getProject()).getToolchain();
|
val toolchain = ZigProjectSettingsService.getInstance(environment.getProject()).getState().getToolchain();
|
||||||
if (toolchain == null) {
|
if (toolchain == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package com.falsepattern.zigbrains.project.toolchain;
|
||||||
import com.falsepattern.zigbrains.project.toolchain.flavours.AbstractZigToolchainFlavour;
|
import com.falsepattern.zigbrains.project.toolchain.flavours.AbstractZigToolchainFlavour;
|
||||||
import com.falsepattern.zigbrains.project.toolchain.tools.ZigCompilerTool;
|
import com.falsepattern.zigbrains.project.toolchain.tools.ZigCompilerTool;
|
||||||
import com.intellij.execution.configurations.GeneralCommandLine;
|
import com.intellij.execution.configurations.GeneralCommandLine;
|
||||||
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
@ -26,8 +27,9 @@ import java.nio.file.Path;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
@Getter
|
||||||
public abstract class AbstractZigToolchain {
|
public abstract class AbstractZigToolchain {
|
||||||
public final Path location;
|
private final Path location;
|
||||||
|
|
||||||
public static @Nullable AbstractZigToolchain suggest() {
|
public static @Nullable AbstractZigToolchain suggest() {
|
||||||
return suggest(null);
|
return suggest(null);
|
||||||
|
|
|
@ -38,6 +38,6 @@ public class LocalZigToolchain extends AbstractZigToolchain{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Path pathToExecutable(String toolName) {
|
public Path pathToExecutable(String toolName) {
|
||||||
return PathUtil.pathToExecutable(location, toolName);
|
return PathUtil.pathToExecutable(getLocation(), toolName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,9 @@ import java.nio.file.Path;
|
||||||
public class ToolchainZLSConfigProvider implements ZLSConfigProvider {
|
public class ToolchainZLSConfigProvider implements ZLSConfigProvider {
|
||||||
@Override
|
@Override
|
||||||
public void getEnvironment(Project project, ZLSConfig.ZLSConfigBuilder builder) {
|
public void getEnvironment(Project project, ZLSConfig.ZLSConfigBuilder builder) {
|
||||||
val projectSettings = ZigProjectSettingsService.getInstance(project);
|
val svc = ZigProjectSettingsService.getInstance(project);
|
||||||
val toolchain = projectSettings.getToolchain();
|
val state = svc.getState();
|
||||||
|
val toolchain = state.getToolchain();
|
||||||
if (toolchain == null)
|
if (toolchain == null)
|
||||||
return;
|
return;
|
||||||
val projectDir = ProjectUtil.guessProjectDir(project);
|
val projectDir = ProjectUtil.guessProjectDir(project);
|
||||||
|
|
|
@ -27,6 +27,7 @@ import lombok.val;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
|
@ -119,4 +120,8 @@ public class CLIUtil {
|
||||||
}
|
}
|
||||||
return result.toArray(new String[0]);
|
return result.toArray(new String[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<String> colored(boolean colored) {
|
||||||
|
return List.of("--color", colored ? "on" : "off");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,13 +32,13 @@
|
||||||
<runLineMarkerContributor language="Zig"
|
<runLineMarkerContributor language="Zig"
|
||||||
implementationClass="com.falsepattern.zigbrains.project.execution.build.ZigLineMarkerBuild"/>
|
implementationClass="com.falsepattern.zigbrains.project.execution.build.ZigLineMarkerBuild"/>
|
||||||
|
|
||||||
<directoryProjectGenerator implementation="com.falsepattern.zigbrains.project.platform.ZigDirectoryProjectGenerator"/>
|
<directoryProjectGenerator implementation="com.falsepattern.zigbrains.project.ide.newproject.ZigDirectoryProjectGenerator"/>
|
||||||
<newProjectWizard.language implementation="com.falsepattern.zigbrains.project.ide.newproject.ZigNewProjectWizard"/>
|
<newProjectWizard.language 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.util.projectwizard.ZigModuleBuilder"/>
|
||||||
<projectConfigurable parentId="language"
|
<projectConfigurable parentId="language"
|
||||||
instance="com.falsepattern.zigbrains.project.ide.project.ZigProjectConfigurable"
|
instance="com.falsepattern.zigbrains.project.ide.config.ZigConfigurable"
|
||||||
id="com.falsepattern.zigbrains.project.ide.project.ZigProjectConfigurable"
|
id="com.falsepattern.zigbrains.project.ide.config.ZigConfigurable"
|
||||||
displayName="Zig"/>
|
displayName="Zig"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
zig-cache/
|
||||||
|
zig-out/
|
||||||
|
build/
|
||||||
|
build-*/
|
||||||
|
docgen_tmp/
|
|
@ -172,23 +172,22 @@ private ContainerMembers ::= ContainerDeclarations (ContainerField COMMA)* (Cont
|
||||||
|
|
||||||
ContainerDeclarations ::= (TestDecl | ComptimeDecl | DOC_COMMENT? KEYWORD_PUB? Decl)*
|
ContainerDeclarations ::= (TestDecl | ComptimeDecl | DOC_COMMENT? KEYWORD_PUB? Decl)*
|
||||||
|
|
||||||
|
TestDecl ::= DOC_COMMENT? KEYWORD_TEST (STRING_LITERAL_SINGLE | IDENTIFIER)? Block {pin=2}
|
||||||
|
|
||||||
TestDecl ::= DOC_COMMENT? KEYWORD_TEST (STRING_LITERAL_SINGLE | IDENTIFIER)? Block
|
ComptimeDecl ::= KEYWORD_COMPTIME Block {pin=1}
|
||||||
|
|
||||||
ComptimeDecl ::= KEYWORD_COMPTIME Block
|
|
||||||
|
|
||||||
Decl
|
Decl
|
||||||
::= (KEYWORD_EXPORT | KEYWORD_EXTERN STRING_LITERAL_SINGLE? | KEYWORD_INLINE | KEYWORD_NOILINE)? FnProto (SEMICOLON | Block)
|
::= (KEYWORD_EXPORT | KEYWORD_EXTERN STRING_LITERAL_SINGLE? | KEYWORD_INLINE | KEYWORD_NOILINE)? FnProto (SEMICOLON | Block)
|
||||||
| (KEYWORD_EXPORT | KEYWORD_EXTERN STRING_LITERAL_SINGLE?)? KEYWORD_THREADLOCAL? GlobalVarDecl
|
| (KEYWORD_EXPORT | KEYWORD_EXTERN STRING_LITERAL_SINGLE?)? KEYWORD_THREADLOCAL? GlobalVarDecl
|
||||||
| KEYWORD_USINGNAMESPACE Expr SEMICOLON
|
| KEYWORD_USINGNAMESPACE Expr SEMICOLON
|
||||||
|
|
||||||
FnProto ::= KEYWORD_FN IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr
|
FnProto ::= KEYWORD_FN IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr {pin=1}
|
||||||
|
|
||||||
VarDeclProto ::= (KEYWORD_CONST | KEYWORD_VAR) IDENTIFIER (COLON TypeExpr)? ByteAlign? AddrSpace? LinkSection?
|
VarDeclProto ::= (KEYWORD_CONST | KEYWORD_VAR) IDENTIFIER (COLON TypeExpr)? ByteAlign? AddrSpace? LinkSection? {pin=1}
|
||||||
|
|
||||||
GlobalVarDecl ::= VarDeclProto (EQUAL Expr)? SEMICOLON
|
GlobalVarDecl ::= VarDeclProto (EQUAL Expr)? SEMICOLON {pin=1}
|
||||||
|
|
||||||
ContainerField ::= DOC_COMMENT? KEYWORD_COMPTUME? !KEYWORD_FN (IDENTIFIER COLON)? TypeExpr ByteAlign? (EQUAL Expr)?
|
ContainerField ::= DOC_COMMENT? KEYWORD_COMPTUME? !KEYWORD_FN (IDENTIFIER COLON)? TypeExpr ByteAlign? (EQUAL Expr)? {pin=5}
|
||||||
|
|
||||||
// *** Block Level ***
|
// *** Block Level ***
|
||||||
Statement
|
Statement
|
||||||
|
@ -207,7 +206,7 @@ ComptimeStatement
|
||||||
|
|
||||||
IfStatement
|
IfStatement
|
||||||
::= IfPrefix BlockExpr ( KEYWORD_ELSE Payload? Statement )?
|
::= IfPrefix BlockExpr ( KEYWORD_ELSE Payload? Statement )?
|
||||||
| IfPrefix AssignExpr ( SEMICOLON | KEYWORD_ELSE Payload? Statement )
|
| IfPrefix AssignExpr ( SEMICOLON | KEYWORD_ELSE Payload? Statement ) {pin(".*")=1}
|
||||||
|
|
||||||
LabeledStatement ::= BlockLabel? (Block | LoopStatement)
|
LabeledStatement ::= BlockLabel? (Block | LoopStatement)
|
||||||
|
|
||||||
|
@ -215,22 +214,24 @@ LoopStatement ::= KEYWORD_INLINE? (ForStatement | WhileStatement)
|
||||||
|
|
||||||
ForStatement
|
ForStatement
|
||||||
::= ForPrefix BlockExpr ( KEYWORD_ELSE Statement )?
|
::= ForPrefix BlockExpr ( KEYWORD_ELSE Statement )?
|
||||||
| ForPrefix AssignExpr ( SEMICOLON | KEYWORD_ELSE Statement )
|
| ForPrefix AssignExpr ( SEMICOLON | KEYWORD_ELSE Statement ) {pin(".*")=1}
|
||||||
|
|
||||||
WhileStatement
|
WhileStatement
|
||||||
::= WhilePrefix BlockExpr ( KEYWORD_ELSE Payload? Statement )?
|
::= WhilePrefix BlockExpr ( KEYWORD_ELSE Payload? Statement )?
|
||||||
| WhilePrefix AssignExpr ( SEMICOLON | KEYWORD_ELSE Payload? Statement)
|
| WhilePrefix AssignExpr ( SEMICOLON | KEYWORD_ELSE Payload? Statement) {pin(".*") =1}
|
||||||
|
|
||||||
BlockExprStatement
|
BlockExprStatement
|
||||||
::= BlockExpr
|
::= BlockExpr
|
||||||
| AssignExpr SEMICOLON
|
| ZB_BlockExprStatement_AssignExpr
|
||||||
|
|
||||||
|
private ZB_BlockExprStatement_AssignExpr ::= AssignExpr SEMICOLON {pin=1}
|
||||||
|
|
||||||
BlockExpr ::= BlockLabel? Block
|
BlockExpr ::= BlockLabel? Block
|
||||||
|
|
||||||
//An expression, assignment, or any destructure, as a statement.
|
//An expression, assignment, or any destructure, as a statement.
|
||||||
VarDeclExprStatement
|
VarDeclExprStatement
|
||||||
::= VarDeclProto (COMMA (VarDeclProto | Expr))* EQUAL Expr SEMICOLON
|
::= VarDeclProto (COMMA (VarDeclProto | Expr))* EQUAL Expr SEMICOLON
|
||||||
| Expr (AssignOp Expr | (COMMA (VarDeclProto | Expr))+ EQUAL Expr)? SEMICOLON
|
| Expr (AssignOp Expr | (COMMA (VarDeclProto | Expr))+ EQUAL Expr)? SEMICOLON {pin(".*")=1}
|
||||||
|
|
||||||
// *** Expression Level ***
|
// *** Expression Level ***
|
||||||
|
|
||||||
|
@ -272,9 +273,11 @@ PrimaryExpr
|
||||||
|
|
||||||
IfExpr ::= IfPrefix Expr (KEYWORD_ELSE Payload? Expr)?
|
IfExpr ::= IfPrefix Expr (KEYWORD_ELSE Payload? Expr)?
|
||||||
|
|
||||||
Block ::= LBRACE ZB_Block_Statement* RBRACE {pin(".*")=1}
|
Block ::= LBRACE ZB_Block_Statement RBRACE {pin(".*")=1}
|
||||||
|
|
||||||
private ZB_Block_Statement ::= Statement {recoverWhile="#auto"}
|
private ZB_Block_Statement ::= Statement* {recoverWhile="ZB_Block_Statement_recover"}
|
||||||
|
|
||||||
|
private ZB_Block_Statement_recover ::= !(RBRACE)
|
||||||
|
|
||||||
LoopExpr ::= KEYWORD_INLINE? (ForExpr | WhileExpr)
|
LoopExpr ::= KEYWORD_INLINE? (ForExpr | WhileExpr)
|
||||||
|
|
||||||
|
@ -379,14 +382,16 @@ ParamType
|
||||||
| TypeExpr
|
| TypeExpr
|
||||||
|
|
||||||
// Control flow prefixes
|
// Control flow prefixes
|
||||||
IfPrefix ::= KEYWORD_IF LPAREN Expr RPAREN PtrPayload?
|
IfPrefix ::= KEYWORD_IF LPAREN Expr RPAREN PtrPayload? {pin=1}
|
||||||
|
|
||||||
WhilePrefix ::= KEYWORD_WHILE LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
|
WhilePrefix ::= KEYWORD_WHILE LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? {pin=1}
|
||||||
|
|
||||||
ForRange ::= Expr DOT2 Expr?
|
ForRange ::= Expr DOT2 Expr?
|
||||||
ForOperand ::= ForRange | Expr
|
ForOperand ::= ForRange | Expr
|
||||||
|
|
||||||
ForPrefix ::= KEYWORD_FOR LPAREN (ForOperand COMMA)* ForOperand RPAREN PtrIndexPayload
|
ForPrefix ::= KEYWORD_FOR LPAREN ZB_ForPrefix_Operands RPAREN PtrIndexPayload {pin=1}
|
||||||
|
|
||||||
|
private ZB_ForPrefix_Operands ::= (ForOperand COMMA)* ForOperand {recoverWhile="#auto"}
|
||||||
|
|
||||||
// Payloads
|
// Payloads
|
||||||
Payload ::= PIPE IDENTIFIER PIPE
|
Payload ::= PIPE IDENTIFIER PIPE
|
||||||
|
@ -485,7 +490,11 @@ SuffixOp
|
||||||
| DOTASTERISK
|
| DOTASTERISK
|
||||||
| DOTQUESTIONMARK
|
| DOTQUESTIONMARK
|
||||||
|
|
||||||
FnCallArguments ::= LPAREN ExprList RPAREN
|
FnCallArguments ::= LPAREN ZB_FnCallArguments_ExprList RPAREN {pin=1}
|
||||||
|
|
||||||
|
private ZB_FnCallArguments_ExprList ::= ExprList {recoverWhile="ZB_FnCallArguments_ExprList_recover"}
|
||||||
|
|
||||||
|
private ZB_FnCallArguments_ExprList_recover ::= !(RPAREN)
|
||||||
|
|
||||||
// Ptr specific
|
// Ptr specific
|
||||||
SliceTypeStart ::= LBRACKET (COLON Expr)? RBRACKET
|
SliceTypeStart ::= LBRACKET (COLON Expr)? RBRACKET
|
||||||
|
@ -498,13 +507,19 @@ PtrTypeStart
|
||||||
ArrayTypeStart ::= LBRACKET Expr (COLON Expr)? RBRACKET
|
ArrayTypeStart ::= LBRACKET Expr (COLON Expr)? RBRACKET
|
||||||
|
|
||||||
// ContainerDecl specific
|
// ContainerDecl specific
|
||||||
ContainerDeclAuto ::= ContainerDeclType LBRACE CONTAINER_DOC_COMMENT? ContainerMembers RBRACE
|
ContainerDeclAuto ::= ContainerDeclType LBRACE CONTAINER_DOC_COMMENT? ZB_ContainerDeclAuto_ContainerMembers RBRACE {pin=2}
|
||||||
|
|
||||||
|
private ZB_ContainerDeclAuto_ContainerMembers ::= ContainerMembers {recoverWhile="ZB_ContainerDeclAuto_ContainerMembers_recover"}
|
||||||
|
private ZB_ContainerDeclAuto_ContainerMembers_recover ::= !(RBRACE)
|
||||||
|
|
||||||
ContainerDeclType
|
ContainerDeclType
|
||||||
::= KEYWORD_STRUCT (LPAREN Expr RPAREN)?
|
::= KEYWORD_STRUCT (LPAREN ZB_ContainerDeclType_Expr RPAREN)?
|
||||||
| KEYWORD_OPAQUE
|
| KEYWORD_OPAQUE
|
||||||
| KEYWORD_ENUM (LPAREN Expr RPAREN)?
|
| KEYWORD_ENUM (LPAREN ZB_ContainerDeclType_Expr RPAREN)?
|
||||||
| KEYWORD_UNION (LPAREN (KEYWORD_ENUM (LPAREN Expr RPAREN)? | Expr) RPAREN)?
|
| KEYWORD_UNION (LPAREN (KEYWORD_ENUM (LPAREN ZB_ContainerDeclType_Expr RPAREN)? | ZB_ContainerDeclType_Expr) RPAREN)? {pin(".*")=1}
|
||||||
|
|
||||||
|
private ZB_ContainerDeclType_Expr ::= Expr {recoverWhile="ZB_ContainerDeclType_Expr_recover"}
|
||||||
|
private ZB_ContainerDeclType_Expr_recover ::= !(RPAREN)
|
||||||
|
|
||||||
// Alignment
|
// Alignment
|
||||||
ByteAlign ::= KEYWORD_ALIGN LPAREN Expr RPAREN
|
ByteAlign ::= KEYWORD_ALIGN LPAREN Expr RPAREN
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.zig.formatter;
|
package com.falsepattern.zigbrains.zig.formatter;
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.zig.psi.ZigTypes;
|
|
||||||
import com.intellij.formatting.Alignment;
|
import com.intellij.formatting.Alignment;
|
||||||
import com.intellij.formatting.Block;
|
import com.intellij.formatting.Block;
|
||||||
import com.intellij.formatting.Indent;
|
import com.intellij.formatting.Indent;
|
||||||
|
@ -35,8 +34,16 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static com.falsepattern.zigbrains.zig.psi.ZigTypes.BLOCK;
|
import static com.falsepattern.zigbrains.zig.psi.ZigTypes.BLOCK;
|
||||||
|
import static com.falsepattern.zigbrains.zig.psi.ZigTypes.CONTAINER_DECL_AUTO;
|
||||||
|
import static com.falsepattern.zigbrains.zig.psi.ZigTypes.CONTAINER_DECL_TYPE;
|
||||||
|
import static com.falsepattern.zigbrains.zig.psi.ZigTypes.CONTAINER_DOC_COMMENT;
|
||||||
import static com.falsepattern.zigbrains.zig.psi.ZigTypes.EXPR_LIST;
|
import static com.falsepattern.zigbrains.zig.psi.ZigTypes.EXPR_LIST;
|
||||||
|
import static com.falsepattern.zigbrains.zig.psi.ZigTypes.FN_CALL_ARGUMENTS;
|
||||||
import static com.falsepattern.zigbrains.zig.psi.ZigTypes.INIT_LIST;
|
import static com.falsepattern.zigbrains.zig.psi.ZigTypes.INIT_LIST;
|
||||||
|
import static com.falsepattern.zigbrains.zig.psi.ZigTypes.LBRACE;
|
||||||
|
import static com.falsepattern.zigbrains.zig.psi.ZigTypes.LPAREN;
|
||||||
|
import static com.falsepattern.zigbrains.zig.psi.ZigTypes.RBRACE;
|
||||||
|
import static com.falsepattern.zigbrains.zig.psi.ZigTypes.RPAREN;
|
||||||
|
|
||||||
public class ZigBlock extends AbstractBlock {
|
public class ZigBlock extends AbstractBlock {
|
||||||
|
|
||||||
|
@ -75,25 +82,26 @@ public class ZigBlock extends AbstractBlock {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected @Nullable Indent getChildIndent() {
|
protected @Nullable Indent getChildIndent() {
|
||||||
return getIndentBasedOnParentType(getNode().getElementType());
|
return getIndentBasedOnParentType(getNode().getElementType(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Indent getIndent() {
|
public Indent getIndent() {
|
||||||
val parent = getNode().getTreeParent();
|
val parent = getNode().getTreeParent();
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
return getIndentBasedOnParentType(parent.getElementType());
|
return getIndentBasedOnParentType(parent.getElementType(), getNode().getElementType());
|
||||||
}
|
}
|
||||||
return Indent.getNoneIndent();
|
return Indent.getNoneIndent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Indent getIndentBasedOnParentType(IElementType elementType) {
|
private static Indent getIndentBasedOnParentType(IElementType parentElementType, IElementType childElementType) {
|
||||||
if (elementType == BLOCK ||
|
if ((parentElementType == BLOCK && childElementType != LBRACE && childElementType != RBRACE) ||
|
||||||
elementType == INIT_LIST ||
|
(parentElementType == INIT_LIST && childElementType != LBRACE && childElementType != RBRACE) ||
|
||||||
elementType == EXPR_LIST) {
|
parentElementType == EXPR_LIST ||
|
||||||
|
(parentElementType == FN_CALL_ARGUMENTS && childElementType != LPAREN && childElementType != RPAREN) ||
|
||||||
|
(parentElementType == CONTAINER_DECL_AUTO && childElementType != CONTAINER_DECL_TYPE && childElementType != LBRACE && childElementType != CONTAINER_DOC_COMMENT && childElementType != RBRACE)) {
|
||||||
return Indent.getNormalIndent();
|
return Indent.getNormalIndent();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Indent.getNoneIndent();
|
return Indent.getNoneIndent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
package com.falsepattern.zigbrains.zig.ide;
|
package com.falsepattern.zigbrains.zig.ide;
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.lsp.contributors.LSPFoldingRangeProvider;
|
import com.falsepattern.zigbrains.lsp.contributors.LSPFoldingRangeProvider;
|
||||||
import com.falsepattern.zigbrains.zig.settings.ZLSSettingsState;
|
import com.falsepattern.zigbrains.zig.settings.ZLSProjectSettingsService;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import org.eclipse.lsp4j.FoldingRange;
|
import org.eclipse.lsp4j.FoldingRange;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
@ -42,6 +42,6 @@ public class ZigFoldingRangeProvider extends LSPFoldingRangeProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean async(Project project) {
|
protected boolean async(Project project) {
|
||||||
return ZLSSettingsState.getInstance(project).asyncFolding;
|
return ZLSProjectSettingsService.getInstance(project).getState().asyncFolding;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ import com.falsepattern.zigbrains.zig.ide.SemaEdit;
|
||||||
import com.falsepattern.zigbrains.zig.util.HighlightingUtil;
|
import com.falsepattern.zigbrains.zig.util.HighlightingUtil;
|
||||||
import com.falsepattern.zigbrains.zig.util.TokenDecoder;
|
import com.falsepattern.zigbrains.zig.util.TokenDecoder;
|
||||||
import com.intellij.lang.annotation.Annotation;
|
import com.intellij.lang.annotation.Annotation;
|
||||||
import com.intellij.openapi.application.ApplicationManager;
|
|
||||||
import com.intellij.openapi.editor.Editor;
|
import com.intellij.openapi.editor.Editor;
|
||||||
import com.intellij.openapi.editor.event.DocumentListener;
|
import com.intellij.openapi.editor.event.DocumentListener;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
|
|
@ -20,7 +20,7 @@ import com.falsepattern.zigbrains.common.util.StringUtil;
|
||||||
import com.falsepattern.zigbrains.lsp.IntellijLanguageClient;
|
import com.falsepattern.zigbrains.lsp.IntellijLanguageClient;
|
||||||
import com.falsepattern.zigbrains.lsp.utils.FileUtils;
|
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.ZLSSettingsState;
|
import com.falsepattern.zigbrains.zig.settings.ZLSProjectSettingsService;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.intellij.notification.Notification;
|
import com.intellij.notification.Notification;
|
||||||
import com.intellij.notification.NotificationType;
|
import com.intellij.notification.NotificationType;
|
||||||
|
@ -54,23 +54,23 @@ public class ZLSStartupActivity implements ProjectActivity {
|
||||||
for (var wrapper : wrappers) {
|
for (var wrapper : wrappers) {
|
||||||
if (wrapper.serverDefinition.ext.equals("zig")) {
|
if (wrapper.serverDefinition.ext.equals("zig")) {
|
||||||
wrapper.stop(false);
|
wrapper.stop(false);
|
||||||
wrapper.removeWidget();
|
|
||||||
IntellijLanguageClient.removeWrapper(wrapper);
|
IntellijLanguageClient.removeWrapper(wrapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var settings = ZLSSettingsState.getInstance(project);
|
var svc = ZLSProjectSettingsService.getInstance(project);
|
||||||
var zlsPath = settings.zlsPath;
|
val state = svc.getState();
|
||||||
|
var zlsPath = state.zlsPath;
|
||||||
if (!validatePath("ZLS Binary", zlsPath, false)) {
|
if (!validatePath("ZLS Binary", zlsPath, false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var configPath = settings.zlsConfigPath;
|
var configPath = state.zlsConfigPath;
|
||||||
boolean configOK = true;
|
boolean configOK = true;
|
||||||
if (!"".equals(configPath) && !validatePath("ZLS Config", configPath, false)) {
|
if (!configPath.isEmpty() && !validatePath("ZLS Config", configPath, false)) {
|
||||||
Notifications.Bus.notify(new Notification("ZigBrains.ZLS", "Using default config path.",
|
Notifications.Bus.notify(new Notification("ZigBrains.ZLS", "Using default config path.",
|
||||||
NotificationType.INFORMATION));
|
NotificationType.INFORMATION));
|
||||||
configPath = "";
|
configPath = null;
|
||||||
}
|
}
|
||||||
if ("".equals(configPath)) {
|
if (configPath == null || configPath.isBlank()) {
|
||||||
blk:
|
blk:
|
||||||
try {
|
try {
|
||||||
val tmpFile = Files.createTempFile("zigbrains-zls-autoconf", ".json");
|
val tmpFile = Files.createTempFile("zigbrains-zls-autoconf", ".json");
|
||||||
|
@ -103,16 +103,16 @@ public class ZLSStartupActivity implements ProjectActivity {
|
||||||
cmd.add(configPath);
|
cmd.add(configPath);
|
||||||
}
|
}
|
||||||
// TODO make this properly configurable
|
// TODO make this properly configurable
|
||||||
if (settings.increaseTimeouts) {
|
if (state.increaseTimeouts) {
|
||||||
for (var timeout : IntellijLanguageClient.getTimeouts().keySet()) {
|
for (var timeout : IntellijLanguageClient.getTimeouts().keySet()) {
|
||||||
IntellijLanguageClient.setTimeout(timeout, 15000);
|
IntellijLanguageClient.setTimeout(timeout, 15000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.debug) {
|
if (state.debug) {
|
||||||
cmd.add("--enable-debug-log");
|
cmd.add("--enable-debug-log");
|
||||||
}
|
}
|
||||||
if (settings.messageTrace) {
|
if (state.messageTrace) {
|
||||||
cmd.add("--enable-message-tracing");
|
cmd.add("--enable-message-tracing");
|
||||||
}
|
}
|
||||||
for (var wrapper : IntellijLanguageClient.getAllServerWrappersFor("zig")) {
|
for (var wrapper : IntellijLanguageClient.getAllServerWrappersFor("zig")) {
|
||||||
|
@ -133,12 +133,16 @@ public class ZLSStartupActivity implements ProjectActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean validatePath(String name, String pathTxt, boolean dir) {
|
private static boolean validatePath(String name, String pathTxt, boolean dir) {
|
||||||
|
if (pathTxt == null || pathTxt.isBlank()) {
|
||||||
|
Notifications.Bus.notify(new Notification("ZigBrains.ZLS", "Missing " + name, "No path was specified", NotificationType.WARNING));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Path path;
|
Path path;
|
||||||
try {
|
try {
|
||||||
path = Path.of(pathTxt);
|
path = Path.of(pathTxt);
|
||||||
} catch (InvalidPathException e) {
|
} catch (InvalidPathException e) {
|
||||||
Notifications.Bus.notify(
|
Notifications.Bus.notify(
|
||||||
new Notification("ZigBrains.ZLS", "No " + name, "Invalid " + name + " path \"" + pathTxt + "\"",
|
new Notification("ZigBrains.ZLS", "No " + name, "Invalid " + name + " at path \"" + pathTxt + "\"",
|
||||||
NotificationType.ERROR));
|
NotificationType.ERROR));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -152,7 +156,7 @@ public class ZLSStartupActivity implements ProjectActivity {
|
||||||
Notifications.Bus.notify(new Notification("ZigBrains.ZLS", "No " + name,
|
Notifications.Bus.notify(new Notification("ZigBrains.ZLS", "No " + name,
|
||||||
"The " + name + " at \"" + pathTxt + "\" is a " +
|
"The " + name + " at \"" + pathTxt + "\" is a " +
|
||||||
(Files.isDirectory(path) ? "directory" : "file") +
|
(Files.isDirectory(path) ? "directory" : "file") +
|
||||||
" , expected a " + (dir ? "directory" : "file"),
|
", expected a " + (dir ? "directory" : "file"),
|
||||||
NotificationType.ERROR));
|
NotificationType.ERROR));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -162,16 +166,15 @@ public class ZLSStartupActivity implements ProjectActivity {
|
||||||
@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) {
|
||||||
var settings = ZLSSettingsState.getInstance(project);
|
val svc = ZLSProjectSettingsService.getInstance(project);
|
||||||
var zlsPath = settings.zlsPath;
|
val state = svc.getState();
|
||||||
|
var zlsPath = state.zlsPath;
|
||||||
|
|
||||||
if (zlsPath.isEmpty() && !settings.initialAutodetectHasBeenDone) {
|
if (zlsPath == null) {
|
||||||
settings.initialAutodetectHasBeenDone = true;
|
//Project creation
|
||||||
var thePath = ZLSSettingsState.executablePathFinder("zls");
|
return null;
|
||||||
if (thePath.isPresent()) {
|
|
||||||
zlsPath = settings.zlsPath = thePath.get();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (zlsPath.isEmpty()) {
|
if (zlsPath.isEmpty()) {
|
||||||
Notifications.Bus.notify(new Notification("ZigBrains.ZLS", "No ZLS binary",
|
Notifications.Bus.notify(new Notification("ZigBrains.ZLS", "No ZLS binary",
|
||||||
"Please configure the path to the zls executable in the Zig language configuration menu!",
|
"Please configure the path to the zls executable in the Zig language configuration menu!",
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* 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.zig.settings;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.common.WrappingStateComponent;
|
||||||
|
import com.intellij.openapi.components.Service;
|
||||||
|
import com.intellij.openapi.components.State;
|
||||||
|
import com.intellij.openapi.components.Storage;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
import lombok.val;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@Service(Service.Level.PROJECT)
|
||||||
|
@State(name = "ZLSSettings",
|
||||||
|
storages = @Storage("zigbrains.xml"))
|
||||||
|
public final class ZLSProjectSettingsService extends WrappingStateComponent<ZLSSettings> {
|
||||||
|
public ZLSProjectSettingsService() {
|
||||||
|
super(new ZLSSettings());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ZLSProjectSettingsService getInstance(Project project) {
|
||||||
|
return project.getService(ZLSProjectSettingsService.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isModified(ZLSSettings otherData) {
|
||||||
|
val myData = this.getState();
|
||||||
|
boolean modified = zlsSettingsModified(otherData);
|
||||||
|
modified |= myData.asyncFolding != otherData.asyncFolding;
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean zlsSettingsModified(ZLSSettings otherData) {
|
||||||
|
val myData = this.getState();
|
||||||
|
boolean modified = !Objects.equals(myData.zlsPath, otherData.zlsPath);
|
||||||
|
modified |= !Objects.equals(myData.zlsConfigPath, otherData.zlsConfigPath);
|
||||||
|
modified |= myData.debug != otherData.debug;
|
||||||
|
modified |= myData.messageTrace != otherData.messageTrace;
|
||||||
|
modified |= myData.increaseTimeouts != otherData.increaseTimeouts;
|
||||||
|
modified |= myData.buildOnSave != otherData.buildOnSave;
|
||||||
|
modified |= !Objects.equals(myData.buildOnSaveStep, otherData.buildOnSaveStep);
|
||||||
|
modified |= myData.highlightGlobalVarDeclarations != otherData.highlightGlobalVarDeclarations;
|
||||||
|
modified |= myData.dangerousComptimeExperimentsDoNotEnable != otherData.dangerousComptimeExperimentsDoNotEnable;
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* 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.zig.settings;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public final class ZLSSettings {
|
||||||
|
public @Nullable String zlsPath;
|
||||||
|
public @NotNull String zlsConfigPath;
|
||||||
|
public boolean increaseTimeouts;
|
||||||
|
public boolean asyncFolding;
|
||||||
|
public boolean debug;
|
||||||
|
public boolean messageTrace;
|
||||||
|
public boolean buildOnSave;
|
||||||
|
public @NotNull String buildOnSaveStep;
|
||||||
|
public boolean highlightGlobalVarDeclarations;
|
||||||
|
public boolean dangerousComptimeExperimentsDoNotEnable;
|
||||||
|
|
||||||
|
public ZLSSettings() {
|
||||||
|
this(null, "", false, true, false, false, false, "install", false, false);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,174 +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.zig.settings;
|
|
||||||
|
|
||||||
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
|
|
||||||
import com.intellij.openapi.ui.TextBrowseFolderListener;
|
|
||||||
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
|
||||||
import com.intellij.ui.components.JBCheckBox;
|
|
||||||
import com.intellij.ui.components.JBLabel;
|
|
||||||
import com.intellij.ui.components.JBTextField;
|
|
||||||
import com.intellij.util.ui.FormBuilder;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
|
|
||||||
public class ZLSSettingsComponent {
|
|
||||||
private final JPanel myMainPanel;
|
|
||||||
private final TextFieldWithBrowseButton zlsPathText = new TextFieldWithBrowseButton();
|
|
||||||
private final TextFieldWithBrowseButton zlsConfigPathText = new TextFieldWithBrowseButton();
|
|
||||||
private final JBCheckBox asyncFoldingCheckBox = new JBCheckBox();
|
|
||||||
private final JBCheckBox increaseTimeouts = new JBCheckBox();
|
|
||||||
|
|
||||||
private final JBCheckBox buildOnSave = new JBCheckBox();
|
|
||||||
private final JBTextField buildOnSaveStep = new JBTextField();
|
|
||||||
private final JBCheckBox highlightGlobalVarDeclarations = new JBCheckBox();
|
|
||||||
private final JBCheckBox dangerousComptimeExperimentsDoNotEnable = new JBCheckBox();
|
|
||||||
|
|
||||||
private final JBCheckBox messageTraceCheckBox = new JBCheckBox();
|
|
||||||
private final JBCheckBox debugCheckBox = new JBCheckBox();
|
|
||||||
|
|
||||||
private final JButton autodetectZls = new JButton("Autodetect");
|
|
||||||
|
|
||||||
{
|
|
||||||
buildOnSave.setToolTipText("Whether to enable build-on-save diagnostics");
|
|
||||||
buildOnSaveStep.setToolTipText("Select which step should be executed on build-on-save");
|
|
||||||
highlightGlobalVarDeclarations.setToolTipText("Whether to highlight global var declarations");
|
|
||||||
dangerousComptimeExperimentsDoNotEnable.setToolTipText("Whether to use the comptime interpreter");
|
|
||||||
}
|
|
||||||
public ZLSSettingsComponent() {
|
|
||||||
zlsPathText.addBrowseFolderListener(
|
|
||||||
new TextBrowseFolderListener(new FileChooserDescriptor(true, false, false, false, false, false)));
|
|
||||||
myMainPanel = FormBuilder.createFormBuilder()
|
|
||||||
.addComponent(new JBLabel("ZLS launch settings"))
|
|
||||||
.addVerticalGap(10)
|
|
||||||
.addLabeledComponent(new JBLabel("ZLS path: "), zlsPathText, 1, false)
|
|
||||||
.addComponent(autodetectZls)
|
|
||||||
.addLabeledComponent(new JBLabel("ZLS config path (leave empty to use built-in config): "),
|
|
||||||
zlsConfigPathText, 1, false)
|
|
||||||
.addLabeledComponent(new JBLabel("Increase timeouts"), increaseTimeouts, 1, false)
|
|
||||||
.addLabeledComponent(new JBLabel("Asynchronous code folding ranges: "),
|
|
||||||
asyncFoldingCheckBox, 1, false)
|
|
||||||
.addSeparator()
|
|
||||||
.addComponent(new JBLabel("ZLS configuration"))
|
|
||||||
.addVerticalGap(10)
|
|
||||||
.addLabeledComponent("Build on save", buildOnSave)
|
|
||||||
.addLabeledComponent("Build on save step", buildOnSaveStep)
|
|
||||||
.addLabeledComponent("Highlight global variable declarations", highlightGlobalVarDeclarations)
|
|
||||||
.addLabeledComponent("Dangerous comptime experiments (do not enable)", dangerousComptimeExperimentsDoNotEnable)
|
|
||||||
.addSeparator()
|
|
||||||
.addComponent(new JBLabel(
|
|
||||||
"Developer settings (only usable when the IDE was launched with " +
|
|
||||||
"the runIDE gradle task in ZigBrains!)"))
|
|
||||||
.addVerticalGap(10)
|
|
||||||
.addLabeledComponent(new JBLabel("ZLS debug log: "), debugCheckBox, 1, false)
|
|
||||||
.addLabeledComponent(new JBLabel("ZLS message trace: "), messageTraceCheckBox, 1,
|
|
||||||
false)
|
|
||||||
.addComponentFillVertically(new JPanel(), 0)
|
|
||||||
.getPanel();
|
|
||||||
autodetectZls.addActionListener(e -> {
|
|
||||||
ZLSSettingsState.executablePathFinder("zls").ifPresent(this::setZLSPath);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public JPanel getPanel() {
|
|
||||||
return myMainPanel;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public String getZLSPath() {
|
|
||||||
return zlsPathText.getText();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setZLSPath(@NotNull String newText) {
|
|
||||||
zlsPathText.setText(newText);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public String getZLSConfigPath() {
|
|
||||||
return zlsConfigPathText.getText();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setZLSConfigPath(@NotNull String newText) {
|
|
||||||
zlsConfigPathText.setText(newText);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getIncreaseTimeouts() {
|
|
||||||
return increaseTimeouts.isSelected();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIncreaseTimeouts(boolean state) {
|
|
||||||
increaseTimeouts.setSelected(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getAsyncFolding() {
|
|
||||||
return asyncFoldingCheckBox.isSelected();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAsyncFolding(boolean state) {
|
|
||||||
asyncFoldingCheckBox.setSelected(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getDebug() {
|
|
||||||
return debugCheckBox.isSelected();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDebug(boolean state) {
|
|
||||||
debugCheckBox.setSelected(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getMessageTrace() {
|
|
||||||
return messageTraceCheckBox.isSelected();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMessageTrace(boolean state) {
|
|
||||||
messageTraceCheckBox.setSelected(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getBuildOnSave() {
|
|
||||||
return buildOnSave.isSelected();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBuildOnSave(boolean state) {
|
|
||||||
buildOnSave.setSelected(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getBuildOnSaveStep() {
|
|
||||||
return buildOnSaveStep.getText();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBuildOnSaveStep(String value) {
|
|
||||||
buildOnSaveStep.setText(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getHighlightGlobalVarDeclarations() {
|
|
||||||
return highlightGlobalVarDeclarations.isSelected();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHighlightGlobalVarDeclarations(boolean state) {
|
|
||||||
highlightGlobalVarDeclarations.setSelected(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getDangerousComptimeExperimentsDoNotEnable() {
|
|
||||||
return dangerousComptimeExperimentsDoNotEnable.isSelected();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDangerousComptimeExperimentsDoNotEnable(boolean state) {
|
|
||||||
dangerousComptimeExperimentsDoNotEnable.setSelected(state);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -24,7 +24,7 @@ import lombok.val;
|
||||||
public class ZLSSettingsConfigProvider implements ZLSConfigProvider {
|
public class ZLSSettingsConfigProvider implements ZLSConfigProvider {
|
||||||
@Override
|
@Override
|
||||||
public void getEnvironment(Project project, ZLSConfig.ZLSConfigBuilder builder) {
|
public void getEnvironment(Project project, ZLSConfig.ZLSConfigBuilder builder) {
|
||||||
val state = ZLSSettingsState.getInstance(project);
|
val state = ZLSProjectSettingsService.getInstance(project).getState();
|
||||||
builder.enable_build_on_save(state.buildOnSave);
|
builder.enable_build_on_save(state.buildOnSave);
|
||||||
builder.build_on_save_step(state.buildOnSaveStep);
|
builder.build_on_save_step(state.buildOnSaveStep);
|
||||||
builder.highlight_global_var_declarations(state.highlightGlobalVarDeclarations);
|
builder.highlight_global_var_declarations(state.highlightGlobalVarDeclarations);
|
||||||
|
|
|
@ -16,16 +16,15 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.zig.settings;
|
package com.falsepattern.zigbrains.zig.settings;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.common.SubConfigurable;
|
||||||
|
import com.falsepattern.zigbrains.common.util.dsl.JavaPanel;
|
||||||
import com.falsepattern.zigbrains.zig.lsp.ZLSStartupActivity;
|
import com.falsepattern.zigbrains.zig.lsp.ZLSStartupActivity;
|
||||||
import com.intellij.openapi.options.Configurable;
|
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
|
import lombok.val;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import javax.swing.JComponent;
|
public class ZLSSettingsConfigurable implements SubConfigurable {
|
||||||
|
private ZLSSettingsPanel appSettingsComponent;
|
||||||
public class ZLSSettingsConfigurable implements Configurable {
|
|
||||||
private ZLSSettingsComponent appSettingsComponent;
|
|
||||||
|
|
||||||
private final Project project;
|
private final Project project;
|
||||||
|
|
||||||
|
@ -34,52 +33,24 @@ public class ZLSSettingsConfigurable implements Configurable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDisplayName() {
|
public void createComponent(JavaPanel panel) {
|
||||||
return "Zig";
|
appSettingsComponent = new ZLSSettingsPanel();
|
||||||
}
|
appSettingsComponent.attachPanelTo(panel);
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable JComponent createComponent() {
|
|
||||||
appSettingsComponent = new ZLSSettingsComponent();
|
|
||||||
return appSettingsComponent.getPanel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isModified() {
|
public boolean isModified() {
|
||||||
var settings = ZLSSettingsState.getInstance(project);
|
var settings = ZLSProjectSettingsService.getInstance(project);
|
||||||
boolean modified = zlsSettingsModified(settings);
|
val data = appSettingsComponent.getData();
|
||||||
modified |= settings.asyncFolding != appSettingsComponent.getAsyncFolding();
|
return settings.isModified(data);
|
||||||
return modified;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean zlsSettingsModified(ZLSSettingsState settings) {
|
|
||||||
boolean modified = !settings.zlsPath.equals(appSettingsComponent.getZLSPath());
|
|
||||||
modified |= !settings.zlsConfigPath.equals(appSettingsComponent.getZLSConfigPath());
|
|
||||||
modified |= settings.debug != appSettingsComponent.getDebug();
|
|
||||||
modified |= settings.messageTrace != appSettingsComponent.getMessageTrace();
|
|
||||||
modified |= settings.increaseTimeouts != appSettingsComponent.getIncreaseTimeouts();
|
|
||||||
modified |= settings.buildOnSave != appSettingsComponent.getBuildOnSave();
|
|
||||||
modified |= !settings.buildOnSaveStep.equals(appSettingsComponent.getBuildOnSaveStep());
|
|
||||||
modified |= settings.highlightGlobalVarDeclarations != appSettingsComponent.getHighlightGlobalVarDeclarations();
|
|
||||||
modified |= settings.dangerousComptimeExperimentsDoNotEnable != appSettingsComponent.getDangerousComptimeExperimentsDoNotEnable();
|
|
||||||
return modified;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void apply() {
|
public void apply() {
|
||||||
var settings = ZLSSettingsState.getInstance(project);
|
var settings = ZLSProjectSettingsService.getInstance(project);
|
||||||
boolean reloadZLS = zlsSettingsModified(settings);
|
val data = appSettingsComponent.getData();
|
||||||
settings.zlsPath = appSettingsComponent.getZLSPath();
|
boolean reloadZLS = settings.zlsSettingsModified(data);
|
||||||
settings.zlsConfigPath = appSettingsComponent.getZLSConfigPath();
|
settings.loadState(data);
|
||||||
settings.asyncFolding = appSettingsComponent.getAsyncFolding();
|
|
||||||
settings.debug = appSettingsComponent.getDebug();
|
|
||||||
settings.messageTrace = appSettingsComponent.getMessageTrace();
|
|
||||||
settings.increaseTimeouts = appSettingsComponent.getIncreaseTimeouts();
|
|
||||||
|
|
||||||
settings.buildOnSave = appSettingsComponent.getBuildOnSave();
|
|
||||||
settings.buildOnSaveStep = appSettingsComponent.getBuildOnSaveStep();
|
|
||||||
settings.highlightGlobalVarDeclarations = appSettingsComponent.getHighlightGlobalVarDeclarations();
|
|
||||||
settings.dangerousComptimeExperimentsDoNotEnable = appSettingsComponent.getDangerousComptimeExperimentsDoNotEnable();
|
|
||||||
if (reloadZLS) {
|
if (reloadZLS) {
|
||||||
ZLSStartupActivity.initZLS(project);
|
ZLSStartupActivity.initZLS(project);
|
||||||
}
|
}
|
||||||
|
@ -87,19 +58,8 @@ public class ZLSSettingsConfigurable implements Configurable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reset() {
|
public void reset() {
|
||||||
var settings = ZLSSettingsState.getInstance(project);
|
var settings = ZLSProjectSettingsService.getInstance(project);
|
||||||
appSettingsComponent.setZLSPath(settings.zlsPath);
|
appSettingsComponent.setData(settings.getState());
|
||||||
appSettingsComponent.setZLSConfigPath(settings.zlsConfigPath);
|
|
||||||
appSettingsComponent.setDebug(settings.debug);
|
|
||||||
appSettingsComponent.setAsyncFolding(settings.asyncFolding);
|
|
||||||
appSettingsComponent.setMessageTrace(settings.messageTrace);
|
|
||||||
appSettingsComponent.setIncreaseTimeouts(settings.increaseTimeouts);
|
|
||||||
appSettingsComponent.setAsyncFolding(settings.asyncFolding);
|
|
||||||
|
|
||||||
appSettingsComponent.setBuildOnSave(settings.buildOnSave);
|
|
||||||
appSettingsComponent.setBuildOnSaveStep(settings.buildOnSaveStep);
|
|
||||||
appSettingsComponent.setHighlightGlobalVarDeclarations(settings.highlightGlobalVarDeclarations);
|
|
||||||
appSettingsComponent.setDangerousComptimeExperimentsDoNotEnable(settings.dangerousComptimeExperimentsDoNotEnable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
/*
|
||||||
|
* 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.zig.settings;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.common.util.FileUtil;
|
||||||
|
import com.falsepattern.zigbrains.common.util.TextFieldUtil;
|
||||||
|
import com.falsepattern.zigbrains.common.util.dsl.JavaPanel;
|
||||||
|
import com.intellij.openapi.Disposable;
|
||||||
|
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
|
||||||
|
import com.intellij.openapi.project.ProjectManager;
|
||||||
|
import com.intellij.openapi.ui.TextBrowseFolderListener;
|
||||||
|
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
||||||
|
import com.intellij.ui.components.JBCheckBox;
|
||||||
|
import com.intellij.ui.components.JBTextField;
|
||||||
|
import com.intellij.ui.components.fields.ExtendableTextField;
|
||||||
|
import com.intellij.ui.dsl.builder.AlignX;
|
||||||
|
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static com.falsepattern.zigbrains.common.util.KtUtil.$f;
|
||||||
|
|
||||||
|
public class ZLSSettingsPanel implements Disposable {
|
||||||
|
private final TextFieldWithBrowseButton zlsPath = TextFieldUtil.pathToFileTextField(this,
|
||||||
|
"Path to the ZLS Binary",
|
||||||
|
() -> {});
|
||||||
|
private final TextFieldWithBrowseButton zlsConfigPath = TextFieldUtil.pathToFileTextField(this,
|
||||||
|
"Path to the Custom ZLS Config File (Optional)",
|
||||||
|
() -> {});
|
||||||
|
private final JBCheckBox asyncFolding = new JBCheckBox();
|
||||||
|
private final JBCheckBox increaseTimeouts = new JBCheckBox();
|
||||||
|
|
||||||
|
private final JBCheckBox buildOnSave = new JBCheckBox();
|
||||||
|
private final JBTextField buildOnSaveStep = new ExtendableTextField();
|
||||||
|
private final JBCheckBox highlightGlobalVarDeclarations = new JBCheckBox();
|
||||||
|
private final JBCheckBox dangerousComptimeExperimentsDoNotEnable = new JBCheckBox();
|
||||||
|
|
||||||
|
private final JBCheckBox messageTrace = new JBCheckBox();
|
||||||
|
private final JBCheckBox debug = new JBCheckBox();
|
||||||
|
|
||||||
|
{
|
||||||
|
buildOnSave.setToolTipText("Whether to enable build-on-save diagnostics");
|
||||||
|
buildOnSaveStep.setToolTipText("Select which step should be executed on build-on-save");
|
||||||
|
highlightGlobalVarDeclarations.setToolTipText("Whether to highlight global var declarations");
|
||||||
|
dangerousComptimeExperimentsDoNotEnable.setToolTipText("Whether to use the comptime interpreter");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void autodetect(ActionEvent e) {
|
||||||
|
autodetect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void autodetect() {
|
||||||
|
FileUtil.findExecutableOnPATH("zls").map(Path::toString).ifPresent(zlsPath::setText);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZLSSettingsPanel() {
|
||||||
|
zlsPath.addBrowseFolderListener(new TextBrowseFolderListener(new FileChooserDescriptor(true, false, false, false, false, false)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void attachPanelTo(JavaPanel panel) {
|
||||||
|
Optional.ofNullable(ZLSProjectSettingsService.getInstance(ProjectManager.getInstance().getDefaultProject()))
|
||||||
|
.map(ZLSProjectSettingsService::getState)
|
||||||
|
.ifPresent(this::setData);
|
||||||
|
panel.group("ZLS launch settings", true, p -> {
|
||||||
|
p.row("Executable path", r -> {
|
||||||
|
r.cell(zlsPath).resizableColumn().align(AlignX.FILL);
|
||||||
|
r.button("Autodetect", $f(this::autodetect));
|
||||||
|
});
|
||||||
|
p.cell("Config path (leave empty to use built-in config)", zlsConfigPath, AlignX.FILL);
|
||||||
|
p.cell("Increase timeouts", increaseTimeouts);
|
||||||
|
p.cell("Asynchronous code folding ranges", asyncFolding);
|
||||||
|
});
|
||||||
|
panel.group("ZLS Configuration", false, p -> {
|
||||||
|
p.cell("Build on save", buildOnSave);
|
||||||
|
p.row("Build on save step", r -> {
|
||||||
|
r.cell(buildOnSaveStep).resizableColumn().align(AlignX.FILL);
|
||||||
|
});
|
||||||
|
p.cell("Highlight global variable declarations", highlightGlobalVarDeclarations);
|
||||||
|
p.cell("Dangerous comptime experiments (do not enable)", dangerousComptimeExperimentsDoNotEnable);
|
||||||
|
});
|
||||||
|
panel.group("ZLS Developer settings", false, p -> {
|
||||||
|
p.cell("Debug log", debug);
|
||||||
|
p.cell("Message trace", messageTrace);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZLSSettings getData() {
|
||||||
|
return new ZLSSettings(zlsPath.getText(),
|
||||||
|
zlsConfigPath.getText(),
|
||||||
|
increaseTimeouts.isSelected(),
|
||||||
|
asyncFolding.isSelected(),
|
||||||
|
debug.isSelected(),
|
||||||
|
messageTrace.isSelected(),
|
||||||
|
buildOnSave.isSelected(),
|
||||||
|
buildOnSaveStep.getText(),
|
||||||
|
highlightGlobalVarDeclarations.isSelected(),
|
||||||
|
dangerousComptimeExperimentsDoNotEnable.isSelected());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(ZLSSettings value) {
|
||||||
|
zlsPath.setText(value.zlsPath == null ? "" : value.zlsPath);
|
||||||
|
zlsConfigPath.setText(value.zlsConfigPath);
|
||||||
|
increaseTimeouts.setSelected(value.increaseTimeouts);
|
||||||
|
asyncFolding.setSelected(value.asyncFolding);
|
||||||
|
debug.setSelected(value.debug);
|
||||||
|
messageTrace.setSelected(value.messageTrace);
|
||||||
|
buildOnSave.setSelected(value.buildOnSave);
|
||||||
|
buildOnSaveStep.setText(value.buildOnSaveStep);
|
||||||
|
highlightGlobalVarDeclarations.setSelected(value.highlightGlobalVarDeclarations);
|
||||||
|
dangerousComptimeExperimentsDoNotEnable.setSelected(value.dangerousComptimeExperimentsDoNotEnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
zlsPath.dispose();
|
||||||
|
zlsConfigPath.dispose();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,85 +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.zig.settings;
|
|
||||||
|
|
||||||
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.openapi.project.Project;
|
|
||||||
import com.intellij.openapi.util.SystemInfo;
|
|
||||||
import com.intellij.util.xmlb.XmlSerializerUtil;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
@Service(Service.Level.PROJECT)
|
|
||||||
@State(name = "ZLSSettings",
|
|
||||||
storages = @Storage("zigbrains.xml"))
|
|
||||||
public final class ZLSSettingsState implements PersistentStateComponent<ZLSSettingsState> {
|
|
||||||
public String zlsPath = "";
|
|
||||||
public String zlsConfigPath = "";
|
|
||||||
public boolean initialAutodetectHasBeenDone = false;
|
|
||||||
public boolean increaseTimeouts = false;
|
|
||||||
public boolean asyncFolding = true;
|
|
||||||
public boolean debug = false;
|
|
||||||
public boolean messageTrace = false;
|
|
||||||
|
|
||||||
public boolean buildOnSave = false;
|
|
||||||
public String buildOnSaveStep = "install";
|
|
||||||
public boolean dangerousComptimeExperimentsDoNotEnable = false;
|
|
||||||
public boolean highlightGlobalVarDeclarations = false;
|
|
||||||
|
|
||||||
public static Optional<String> executablePathFinder(String exe) {
|
|
||||||
var exeName = SystemInfo.isWindows ? exe + ".exe" : exe;
|
|
||||||
var PATH = System.getenv("PATH").split(File.pathSeparator);
|
|
||||||
for (var dir: PATH) {
|
|
||||||
var path = Path.of(dir);
|
|
||||||
try {
|
|
||||||
path = path.toAbsolutePath();
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!Files.exists(path) || !Files.isDirectory(path)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var exePath = path.resolve(exeName).toAbsolutePath();
|
|
||||||
if (!Files.isRegularFile(exePath) || !Files.isExecutable(exePath)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
return Optional.of(exePath.toString());
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ZLSSettingsState getInstance(Project project) {
|
|
||||||
return project.getService(ZLSSettingsState.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ZLSSettingsState getState() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void loadState(@NotNull ZLSSettingsState state) {
|
|
||||||
XmlSerializerUtil.copyBean(state, this);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -98,11 +98,6 @@
|
||||||
|
|
||||||
<lang.formatter language="Zig" implementationClass="com.falsepattern.zigbrains.zig.formatter.ZigFormattingModelBuilder"/>
|
<lang.formatter language="Zig" implementationClass="com.falsepattern.zigbrains.zig.formatter.ZigFormattingModelBuilder"/>
|
||||||
|
|
||||||
<projectConfigurable parentId="language"
|
|
||||||
instance="com.falsepattern.zigbrains.zig.settings.ZLSSettingsConfigurable"
|
|
||||||
id="com.falsepattern.zigbrains.zig.settings.ZLSSettingsConfigurable"
|
|
||||||
displayName="ZLS"/>
|
|
||||||
|
|
||||||
<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.zig.Bundle"
|
||||||
|
@ -113,6 +108,8 @@
|
||||||
implementationClass="com.falsepattern.zigbrains.zig.completion.ZigParameterInfoHandler"/>
|
implementationClass="com.falsepattern.zigbrains.zig.completion.ZigParameterInfoHandler"/>
|
||||||
|
|
||||||
<platform.backend.documentation.linkHandler implementation="com.falsepattern.zigbrains.lsp.contributors.LSPDocumentationLinkHandler"/>
|
<platform.backend.documentation.linkHandler implementation="com.falsepattern.zigbrains.lsp.contributors.LSPDocumentationLinkHandler"/>
|
||||||
|
|
||||||
|
<dynamicActionConfigurationCustomizer implementation="com.falsepattern.zigbrains.lsp.actions.ActionCustomizer"/>
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="com.falsepattern.zigbrains">
|
<extensions defaultExtensionNs="com.falsepattern.zigbrains">
|
||||||
|
@ -130,15 +127,6 @@
|
||||||
<keyboard-shortcut first-keystroke="shift alt F7"
|
<keyboard-shortcut first-keystroke="shift alt F7"
|
||||||
keymap="$default"/>
|
keymap="$default"/>
|
||||||
</action>
|
</action>
|
||||||
<action class="com.falsepattern.zigbrains.lsp.actions.LSPReformatAction" id="ReformatCode" use-shortcut-of="ReformatCode"
|
|
||||||
overrides="true" text="Reformat Code"/>
|
|
||||||
<action class="com.falsepattern.zigbrains.lsp.actions.LSPGotoDeclarationAction" id="GotoDeclaration" use-shortcut-of="GotoDeclaration"
|
|
||||||
overrides="true" text="Go to Declaration or Usages"/>
|
|
||||||
<action class="com.falsepattern.zigbrains.lsp.actions.LSPGotoDefinitionAction" id="QuickImplementations" use-shortcut-of="QuickImplementations"
|
|
||||||
overrides="true" text="View Implementations"/>
|
|
||||||
<action class="com.falsepattern.zigbrains.lsp.actions.LSPShowReformatDialogAction" id="ShowReformatFileDialog"
|
|
||||||
use-shortcut-of="ShowReformatFileDialog" overrides="true" text="Show Reformat File Dialog"/>
|
|
||||||
|
|
||||||
<!-- endregion LSP -->
|
<!-- endregion LSP -->
|
||||||
</actions>
|
</actions>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue