feat(config): Reimplemented config backend, much more reliable and extensible now.
This commit is contained in:
parent
2d1620f86d
commit
bc408b1d50
18 changed files with 583 additions and 230 deletions
|
@ -39,6 +39,10 @@ Changelog structure reference:
|
|||
|
||||
- NullPointerException in folding range provider when closing editors quickly
|
||||
|
||||
#### Config
|
||||
|
||||
- Changes to the ZLS configuration no longer require an IDE restart
|
||||
|
||||
## [0.6.0]
|
||||
|
||||
### Added
|
||||
|
|
|
@ -27,6 +27,7 @@ import com.intellij.openapi.application.ApplicationManager;
|
|||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
|
@ -46,7 +47,6 @@ import java.util.concurrent.CompletableFuture;
|
|||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class LSPFoldingRangeProvider extends CustomFoldingBuilder {
|
||||
private static final Key<Boolean> ASYNC_FOLDING_KEY = new Key<>("ASYNC_FOLDING");
|
||||
|
@ -76,7 +76,7 @@ public class LSPFoldingRangeProvider extends CustomFoldingBuilder {
|
|||
return;
|
||||
}
|
||||
|
||||
var async = async();
|
||||
var async = async(root.getProject());
|
||||
if (!async) {
|
||||
doBuildLanguageFoldRegions((start, end, collapsedText) -> {
|
||||
if (collapsedText != null) {
|
||||
|
@ -186,7 +186,7 @@ public class LSPFoldingRangeProvider extends CustomFoldingBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
protected boolean async() {
|
||||
protected boolean async(Project project) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright 2023 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.settings;
|
||||
|
||||
import com.intellij.openapi.options.Configurable;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.util.NlsContexts;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public abstract class AbstractConfigurable<T> implements Configurable {
|
||||
private final String displayName;
|
||||
private final Supplier<ConfigurableGui<T>> guiSupplier;
|
||||
protected ConfigurableGui<T> configurableGui;
|
||||
|
||||
public AbstractConfigurable(MethodHandles.Lookup lookup, String displayName, Class<T> holderClass)
|
||||
throws IllegalAccessException {
|
||||
this.displayName = displayName;
|
||||
guiSupplier = ConfigurableGui.create(lookup, holderClass);
|
||||
}
|
||||
|
||||
protected abstract T getHolder();
|
||||
|
||||
@Override
|
||||
public @NlsContexts.ConfigurableName String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable JComponent createComponent() {
|
||||
configurableGui = guiSupplier.get();
|
||||
return configurableGui.getPanel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isModified() {
|
||||
return configurableGui.modified(getHolder());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply() throws ConfigurationException {
|
||||
configurableGui.guiToConfig(getHolder());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
configurableGui.configToGui(getHolder());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disposeUIResources() {
|
||||
configurableGui = null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2023 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.settings;
|
||||
|
||||
import com.intellij.ui.TextAccessor;
|
||||
import com.intellij.ui.components.JBCheckBox;
|
||||
|
||||
public interface ConfigurableAccessor<T> {
|
||||
T get();
|
||||
void set(Object value);
|
||||
|
||||
record TextFieldAccessor(TextAccessor accessor) implements ConfigurableAccessor<String> {
|
||||
|
||||
@Override
|
||||
public String get() {
|
||||
return accessor.getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Object value) {
|
||||
accessor.setText((String)value);
|
||||
}
|
||||
}
|
||||
|
||||
record CheckBoxAccessor(JBCheckBox checkBox) implements ConfigurableAccessor<Boolean> {
|
||||
@Override
|
||||
public Boolean get() {
|
||||
return checkBox.isSelected() == Boolean.TRUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Object value) {
|
||||
checkBox.setSelected(value == Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* Copyright 2023 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.settings;
|
||||
|
||||
import com.falsepattern.zigbrains.settings.annotations.Category;
|
||||
import com.falsepattern.zigbrains.settings.annotations.Config;
|
||||
import com.falsepattern.zigbrains.settings.annotations.FilePath;
|
||||
import com.falsepattern.zigbrains.settings.annotations.Label;
|
||||
import com.falsepattern.zigbrains.settings.annotations.Separator;
|
||||
import com.falsepattern.zigbrains.settings.annotations.VerticalGap;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
|
||||
import com.intellij.openapi.ui.TextBrowseFolderListener;
|
||||
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
||||
import com.intellij.ui.TextAccessor;
|
||||
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 javax.swing.JComponent;
|
||||
import javax.swing.JPanel;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ConfigurableGui<T> {
|
||||
private final JPanel thePanel;
|
||||
|
||||
private final Map<String, ConfigurableAccessor<?>> guiProps;
|
||||
private final Map<String, VarHandle> configProps;
|
||||
private final Set<String> props;
|
||||
private ConfigurableGui(JPanel thePanel,
|
||||
Map<String, ConfigurableAccessor<?>> guiProps,
|
||||
Map<String, VarHandle> configProps,
|
||||
Set<String> props) {
|
||||
this.thePanel = thePanel;
|
||||
this.guiProps = guiProps;
|
||||
this.configProps = configProps;
|
||||
this.props = props;
|
||||
}
|
||||
|
||||
public JPanel getPanel() {
|
||||
return thePanel;
|
||||
}
|
||||
|
||||
public boolean modified(T holder) {
|
||||
return modified(holder, false, null);
|
||||
}
|
||||
|
||||
public boolean modified(T holder, boolean exclude, Set<String> mask) {
|
||||
for (var prop: props) {
|
||||
if (mask != null && mask.contains(prop) == exclude) {
|
||||
continue;
|
||||
}
|
||||
if (!Objects.equals(guiProps.get(prop).get(), configProps.get(prop).get(holder))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void guiToConfig(T holder) {
|
||||
for (var prop: props) {
|
||||
configProps.get(prop).set(holder, guiProps.get(prop).get());
|
||||
}
|
||||
}
|
||||
|
||||
public void configToGui(T holder) {
|
||||
for (var prop: props) {
|
||||
guiProps.get(prop).set(configProps.get(prop).get(holder));
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> Supplier<ConfigurableGui<T>> create(MethodHandles.Lookup lookup, Class<T> dataContainer)
|
||||
throws IllegalAccessException {
|
||||
var fields = Arrays.stream(dataContainer.getFields())
|
||||
.filter(field -> field.isAnnotationPresent(Config.class))
|
||||
.filter(field -> field.isAnnotationPresent(Label.class))
|
||||
.sorted(Comparator.comparingInt(field -> field.getAnnotation(Config.class).value()))
|
||||
.toList();
|
||||
var configProps = new HashMap<String, VarHandle>();
|
||||
var props = new HashSet<String>();
|
||||
var steps = new ArrayList<BiConsumer<HashMap<String, ConfigurableAccessor<?>>, FormBuilder>>();
|
||||
for (var field: fields) {
|
||||
var propName = field.getName();
|
||||
var fieldType = field.getType();
|
||||
var label = field.getAnnotation(Label.class).value();
|
||||
if (field.isAnnotationPresent(VerticalGap.class)) {
|
||||
var gap = field.getAnnotation(VerticalGap.class).value();
|
||||
steps.add((gp, fb) -> fb.addVerticalGap(gap));
|
||||
}
|
||||
if (field.isAnnotationPresent(Separator.class)) {
|
||||
steps.add((gp, fb) -> fb.addSeparator());
|
||||
}
|
||||
if (field.isAnnotationPresent(Category.class)) {
|
||||
var cat = field.getAnnotation(Category.class).value();
|
||||
steps.add((gp, fb) -> fb.addSeparator()
|
||||
.addComponent(new JBLabel(cat))
|
||||
.addVerticalGap(10));
|
||||
}
|
||||
Function<HashMap<String, ConfigurableAccessor<?>>, JComponent> component;
|
||||
if (fieldType.equals(String.class)) {
|
||||
var isFilePath = field.isAnnotationPresent(FilePath.class);
|
||||
if (isFilePath) {
|
||||
var filePathSpec = field.getAnnotation(FilePath.class);
|
||||
var descriptor = new FileChooserDescriptor(filePathSpec.files(),
|
||||
filePathSpec.folders(),
|
||||
filePathSpec.jars(),
|
||||
filePathSpec.jarsAsFiles(),
|
||||
filePathSpec.jarContents(),
|
||||
filePathSpec.multiple());
|
||||
component = (guiProps) -> {
|
||||
var theComponent = new TextFieldWithBrowseButton();
|
||||
theComponent.addBrowseFolderListener(new TextBrowseFolderListener(descriptor));
|
||||
guiProps.put(propName, new ConfigurableAccessor.TextFieldAccessor(theComponent));
|
||||
return theComponent;
|
||||
};
|
||||
} else {
|
||||
component = (guiProps) -> {
|
||||
var theComponent = new JBTextField();
|
||||
guiProps.put(propName, new ConfigurableAccessor.TextFieldAccessor(theComponent));
|
||||
return theComponent;
|
||||
};
|
||||
}
|
||||
} else if (fieldType.equals(boolean.class)) {
|
||||
component = (guiProps) -> {
|
||||
var theComponent = new JBCheckBox();
|
||||
guiProps.put(propName, new ConfigurableAccessor.CheckBoxAccessor(theComponent));
|
||||
return theComponent;
|
||||
};
|
||||
} else {
|
||||
component = null;
|
||||
}
|
||||
if (component != null) {
|
||||
props.add(propName);
|
||||
configProps.put(propName, lookup.unreflectVarHandle(field));
|
||||
}
|
||||
steps.add((gp, fb) -> {
|
||||
var comp = component == null ? null : component.apply(gp);
|
||||
if (comp != null) {
|
||||
fb.addLabeledComponent(new JBLabel(label), comp, 1, false);
|
||||
} else {
|
||||
fb.addComponent(new JBLabel(label));
|
||||
}
|
||||
});
|
||||
}
|
||||
steps.add((gp, fb) -> fb.addComponentFillVertically(new JPanel(), 0));
|
||||
|
||||
return () -> {
|
||||
var gp = new HashMap<String, ConfigurableAccessor<?>>();
|
||||
var fb = FormBuilder.createFormBuilder();
|
||||
for (var step: steps) {
|
||||
step.accept(gp, fb);
|
||||
}
|
||||
for (var prop: props) {
|
||||
|
||||
}
|
||||
return new ConfigurableGui<>(fb.getPanel(), gp, configProps, props);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright 2023 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.settings.annotations;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Category {
|
||||
String value();
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright 2023 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.settings.annotations;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Config {
|
||||
int value();
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2023 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.settings.annotations;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface FilePath {
|
||||
boolean files() default false;
|
||||
boolean folders() default false;
|
||||
boolean jars() default false;
|
||||
boolean jarsAsFiles() default false;
|
||||
boolean jarContents() default false;
|
||||
boolean multiple() default false;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright 2023 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.settings.annotations;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Label {
|
||||
String value();
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 2023 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.settings.annotations;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Separator {
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright 2023 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.settings.annotations;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface VerticalGap {
|
||||
int value();
|
||||
}
|
|
@ -16,7 +16,8 @@
|
|||
|
||||
package com.falsepattern.zigbrains.zig.ide;
|
||||
|
||||
import com.falsepattern.zigbrains.zig.settings.AppSettingsState;
|
||||
import com.falsepattern.zigbrains.zig.settings.ZLSSettingsState;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.eclipse.lsp4j.FoldingRange;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
@ -40,7 +41,7 @@ public class ZigFoldingRangeProvider extends LSPFoldingRangeProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean async() {
|
||||
return AppSettingsState.getInstance().asyncFolding;
|
||||
protected boolean async(Project project) {
|
||||
return ZLSSettingsState.getInstance(project).asyncFolding;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
|
||||
package com.falsepattern.zigbrains.zig.lsp;
|
||||
|
||||
import com.falsepattern.zigbrains.zig.settings.AppSettingsState;
|
||||
import com.falsepattern.zigbrains.lsp.utils.FileUtils;
|
||||
import com.falsepattern.zigbrains.zig.settings.ZLSSettingsState;
|
||||
import com.intellij.notification.Notification;
|
||||
import com.intellij.notification.NotificationType;
|
||||
import com.intellij.notification.Notifications;
|
||||
|
@ -38,11 +39,19 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||
public class ZLSStartupActivity implements ProjectActivity {
|
||||
private static final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
public static void initZLS() {
|
||||
public static void initZLS(Project project) {
|
||||
ApplicationManager.getApplication().executeOnPooledThread(() -> {
|
||||
lock.lock();
|
||||
try {
|
||||
var settings = AppSettingsState.getInstance();
|
||||
var wrappers = IntellijLanguageClient.getAllServerWrappersFor(FileUtils.projectToUri(project));
|
||||
for (var wrapper : wrappers) {
|
||||
if (wrapper.serverDefinition.ext.equals("zig")) {
|
||||
wrapper.stop(false);
|
||||
wrapper.stop(true);
|
||||
IntellijLanguageClient.removeWrapper(wrapper);
|
||||
}
|
||||
}
|
||||
var settings = ZLSSettingsState.getInstance(project);
|
||||
var zlsPath = settings.zlsPath;
|
||||
if (!validatePath("ZLS Binary", zlsPath, false)) {
|
||||
return;
|
||||
|
@ -90,7 +99,7 @@ public class ZLSStartupActivity implements ProjectActivity {
|
|||
}
|
||||
}
|
||||
}
|
||||
IntellijLanguageClient.addServerDefinition(new ZLSServerDefinition(cmd.toArray(String[]::new)));
|
||||
IntellijLanguageClient.addServerDefinition(new ZLSServerDefinition(cmd.toArray(String[]::new)), project);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
@ -127,14 +136,14 @@ public class ZLSStartupActivity implements ProjectActivity {
|
|||
@Nullable
|
||||
@Override
|
||||
public Object execute(@NotNull Project project, @NotNull Continuation<? super Unit> continuation) {
|
||||
var path = AppSettingsState.getInstance().zlsPath;
|
||||
var path = ZLSSettingsState.getInstance(project).zlsPath;
|
||||
if ("".equals(path)) {
|
||||
Notifications.Bus.notify(new Notification("ZigBrains.Nag", "No ZLS binary",
|
||||
"Please configure the path to the zls executable in the Zig language configuration menu!",
|
||||
NotificationType.INFORMATION));
|
||||
return null;
|
||||
}
|
||||
initZLS();
|
||||
initZLS(project);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,115 +0,0 @@
|
|||
/*
|
||||
* Copyright 2023 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.util.ui.FormBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
public class AppSettingsComponent {
|
||||
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 debugCheckBox = new JBCheckBox();
|
||||
private final JBCheckBox messageTraceCheckBox = new JBCheckBox();
|
||||
private final JBCheckBox increaseTimeouts = new JBCheckBox();
|
||||
|
||||
public AppSettingsComponent() {
|
||||
zlsPathText.addBrowseFolderListener(
|
||||
new TextBrowseFolderListener(new FileChooserDescriptor(true, false, false, false, false, false)));
|
||||
myMainPanel = FormBuilder.createFormBuilder()
|
||||
.addComponent(new JBLabel("Regular settings"))
|
||||
.addVerticalGap(10)
|
||||
.addLabeledComponent(new JBLabel("ZLS path: "), zlsPathText, 1, false)
|
||||
.addLabeledComponent(new JBLabel("ZLS config path (leave empty to use default): "),
|
||||
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(
|
||||
"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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* Copyright 2023 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.zig.lsp.ZLSStartupActivity;
|
||||
import com.intellij.openapi.options.Configurable;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
|
||||
public class AppSettingsConfigurable implements Configurable {
|
||||
private AppSettingsComponent appSettingsComponent;
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "Zig";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable JComponent createComponent() {
|
||||
appSettingsComponent = new AppSettingsComponent();
|
||||
return appSettingsComponent.getPanel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isModified() {
|
||||
var settings = AppSettingsState.getInstance();
|
||||
boolean modified = zlsSettingsModified(settings);
|
||||
modified |= settings.asyncFolding != appSettingsComponent.getAsyncFolding();
|
||||
return modified;
|
||||
}
|
||||
|
||||
private boolean zlsSettingsModified(AppSettingsState 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();
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply() {
|
||||
var settings = AppSettingsState.getInstance();
|
||||
boolean reloadZLS = zlsSettingsModified(settings);
|
||||
settings.zlsPath = appSettingsComponent.getZLSPath();
|
||||
settings.zlsConfigPath = appSettingsComponent.getZLSConfigPath();
|
||||
settings.asyncFolding = appSettingsComponent.getAsyncFolding();
|
||||
settings.debug = appSettingsComponent.getDebug();
|
||||
settings.messageTrace = appSettingsComponent.getMessageTrace();
|
||||
settings.increaseTimeouts = appSettingsComponent.getIncreaseTimeouts();
|
||||
if (reloadZLS) {
|
||||
ZLSStartupActivity.initZLS();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
var settings = AppSettingsState.getInstance();
|
||||
appSettingsComponent.setZLSPath(settings.zlsPath);
|
||||
appSettingsComponent.setZLSConfigPath(settings.zlsConfigPath);
|
||||
appSettingsComponent.setDebug(settings.debug);
|
||||
appSettingsComponent.setAsyncFolding(settings.asyncFolding);
|
||||
appSettingsComponent.setMessageTrace(settings.messageTrace);
|
||||
appSettingsComponent.setIncreaseTimeouts(settings.increaseTimeouts);
|
||||
appSettingsComponent.setAsyncFolding(settings.asyncFolding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disposeUIResources() {
|
||||
appSettingsComponent = null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright 2023 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.settings.AbstractConfigurable;
|
||||
import com.falsepattern.zigbrains.zig.lsp.ZLSStartupActivity;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Set;
|
||||
|
||||
public class ZLSSettingsConfigurable extends AbstractConfigurable<ZLSSettingsState> {
|
||||
private static final MethodHandles.Lookup LOOKUP = MethodHandles.publicLookup();
|
||||
|
||||
private static final Set<String> RELOAD_CONFIGS = Set.of("zlsPath", "zlsConfigPath", "increaseTimeouts", "debug", "messageTrace");
|
||||
|
||||
private final Project project;
|
||||
|
||||
public ZLSSettingsConfigurable(@NotNull Project project) throws IllegalAccessException {
|
||||
super(LOOKUP, "Zig", ZLSSettingsState.class);
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply() throws ConfigurationException {
|
||||
boolean reloadZLS = zlsSettingsModified();
|
||||
super.apply();
|
||||
if (reloadZLS) {
|
||||
ZLSStartupActivity.initZLS(project);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean zlsSettingsModified() {
|
||||
if (configurableGui != null) {
|
||||
return configurableGui.modified(getHolder(), false, RELOAD_CONFIGS);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ZLSSettingsState getHolder() {
|
||||
return ZLSSettingsState.getInstance(project);
|
||||
}
|
||||
}
|
|
@ -16,36 +16,56 @@
|
|||
|
||||
package com.falsepattern.zigbrains.zig.settings;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.falsepattern.zigbrains.settings.annotations.Category;
|
||||
import com.falsepattern.zigbrains.settings.annotations.Config;
|
||||
import com.falsepattern.zigbrains.settings.annotations.FilePath;
|
||||
import com.falsepattern.zigbrains.settings.annotations.Label;
|
||||
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.util.xmlb.XmlSerializerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@Service(Service.Level.APP)
|
||||
@State(name = "com.falsepattern.zigbrains.zig.settings.AppSettingsState",
|
||||
storages = @Storage("ZigBrainsSettings.xml"))
|
||||
public final class AppSettingsState implements PersistentStateComponent<AppSettingsState> {
|
||||
@Service(Service.Level.PROJECT)
|
||||
@State(name = "ZLSSettings",
|
||||
storages = @Storage("zigbrains.xml"))
|
||||
public final class ZLSSettingsState implements PersistentStateComponent<ZLSSettingsState> {
|
||||
@Category("Regular settings")
|
||||
@Config(0)
|
||||
@Label("ZLS path: ")
|
||||
@FilePath(files = true)
|
||||
public String zlsPath = "";
|
||||
@Config(10)
|
||||
@Label("ZLS config path (leave empty to use default): ")
|
||||
@FilePath(files = true)
|
||||
public String zlsConfigPath = "";
|
||||
public boolean debug = false;
|
||||
public boolean asyncFolding = true;
|
||||
public boolean messageTrace = false;
|
||||
@Config(20)
|
||||
@Label("Increase timeouts")
|
||||
public boolean increaseTimeouts = false;
|
||||
@Config(30)
|
||||
@Label("Asynchronous code folding ranges: ")
|
||||
public boolean asyncFolding = true;
|
||||
@Category("Developer settings (only usable when the IDE was launched with the runIDE gradle task in ZigBrains!)")
|
||||
@Config(40)
|
||||
@Label("ZLS debug log: ")
|
||||
public boolean debug = false;
|
||||
@Config(50)
|
||||
@Label("ZLS message trace: ")
|
||||
public boolean messageTrace = false;
|
||||
|
||||
public static AppSettingsState getInstance() {
|
||||
return ApplicationManager.getApplication().getService(AppSettingsState.class);
|
||||
public static ZLSSettingsState getInstance(Project project) {
|
||||
return project.getService(ZLSSettingsState.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppSettingsState getState() {
|
||||
public ZLSSettingsState getState() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadState(@NotNull AppSettingsState state) {
|
||||
public void loadState(@NotNull ZLSSettingsState state) {
|
||||
XmlSerializerUtil.copyBean(state, this);
|
||||
}
|
||||
}
|
|
@ -86,10 +86,10 @@
|
|||
<lang.braceMatcher language="Zig"
|
||||
implementationClass="com.falsepattern.zigbrains.zig.pairing.ZigBraceMatcher"/>
|
||||
|
||||
<applicationConfigurable parentId="language"
|
||||
instance="com.falsepattern.zigbrains.zig.settings.AppSettingsConfigurable"
|
||||
id="com.falsepattern.zigbrains.zig.settings.AppSettingsConfigurable"
|
||||
displayName="Zig"/>
|
||||
<projectConfigurable parentId="language"
|
||||
instance="com.falsepattern.zigbrains.zig.settings.ZLSSettingsConfigurable"
|
||||
id="com.falsepattern.zigbrains.zig.settings.ZLSSettingsConfigurable"
|
||||
displayName="Zig"/>
|
||||
|
||||
<postStartupActivity implementation="com.falsepattern.zigbrains.zig.lsp.ZLSStartupActivity"/>
|
||||
<notificationGroup displayType="BALLOON"
|
||||
|
|
Loading…
Add table
Reference in a new issue