backport: 13.0.1

ci: 13.0.1

fix: Semantic highlighting broken on editor split

fix: Shotgun null safety fixes
This commit is contained in:
FalsePattern 2024-03-12 22:10:47 +01:00
parent 8ea6447855
commit 55997acb45
Signed by: falsepattern
GPG key ID: E930CDEC50C50E23
15 changed files with 99 additions and 53 deletions

View file

@ -18,7 +18,13 @@ Changelog structure reference:
## [Unreleased] ## [Unreleased]
## [13.0.0] ## [13.0.1]
### HOTFIX CHANGES
- Fixed multiple critical null safety problems that caused plugin crashes on some systems
- Splitting the editor now no longer breaks semantic highlighting
The rest of the 13.0.0 changes are available below:
### Added ### Added

View file

@ -17,6 +17,7 @@
package com.falsepattern.zigbrains.common.util; package com.falsepattern.zigbrains.common.util;
import lombok.val; import lombok.val;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays; import java.util.Arrays;
@ -29,6 +30,9 @@ public class StringUtil {
return value == null ? "" : value; return value == null ? "" : value;
} }
public static boolean isEmpty(@Nullable String str) {
return str == null || str.isEmpty();
}
private static final char[] VT100_CHARS = new char[256]; private static final char[] VT100_CHARS = new char[256];

View file

@ -782,7 +782,7 @@ public abstract class DAPDriver<
for (val registerGroup: registerGroups) { for (val registerGroup: registerGroups) {
val name = (c++) + " - " + registerGroup.getName(); val name = (c++) + " - " + registerGroup.getName();
val ref = registerGroup.getUserData(LLVALUE_CHILDREN_REF); val ref = registerGroup.getUserData(LLVALUE_CHILDREN_REF);
if (ref == 0) if (ref == null || ref == 0)
continue; continue;
val registers = getVariables(frameID, ref, null, null); val registers = getVariables(frameID, ref, null, null);
val renamedRegisters = new ArrayList<LLValue>(); val renamedRegisters = new ArrayList<LLValue>();

View file

@ -21,6 +21,7 @@ import com.falsepattern.zigbrains.debugger.dap.WrappedDebugServer;
import com.intellij.execution.ExecutionException; import com.intellij.execution.ExecutionException;
import com.intellij.util.system.CpuArch; import com.intellij.util.system.CpuArch;
import com.jetbrains.cidr.ArchitectureType; import com.jetbrains.cidr.ArchitectureType;
import lombok.Cleanup;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.NonNull; import lombok.NonNull;
@ -112,7 +113,11 @@ public class WinDAPDriver extends DAPDriver<
val hasher = MessageDigest.getInstance("SHA-256"); val hasher = MessageDigest.getInstance("SHA-256");
hasher.update(handshake.getValue().getBytes(StandardCharsets.UTF_8)); hasher.update(handshake.getValue().getBytes(StandardCharsets.UTF_8));
var inflater = new Inflater(true); var inflater = new Inflater(true);
val coconut = DAPDebuggerClient.class.getResourceAsStream("/coconut.jpg").readAllBytes(); @Cleanup val coconutJpg = DAPDebuggerClient.class.getResourceAsStream("/coconut.jpg");
if (coconutJpg == null) {
throw new RuntimeException("No coconut");
}
val coconut = coconutJpg.readAllBytes();
inflater.setInput(coconut, coconut.length - 80, 77); inflater.setInput(coconut, coconut.length - 80, 77);
inflater.finished(); inflater.finished();
var b = new byte[1]; var b = new byte[1];

View file

@ -46,32 +46,37 @@ public class LSPShowReformatDialogAction extends ShowReformatFileDialog implemen
Editor editor = e.getData(CommonDataKeys.EDITOR); Editor editor = e.getData(CommonDataKeys.EDITOR);
Project project = e.getData(CommonDataKeys.PROJECT); Project project = e.getData(CommonDataKeys.PROJECT);
if (editor != null && project != null) { if (editor == null || project == null) {
PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
VirtualFile virFile = FileDocumentManager.getInstance().getFile(editor.getDocument());
if (IntellijLanguageClient.isExtensionSupported(virFile)) {
boolean hasSelection = editor.getSelectionModel().hasSelection();
LayoutCodeDialog dialog = new LayoutCodeDialog(project, psiFile, hasSelection, HELP_ID);
dialog.show();
if (dialog.isOK()) {
LayoutCodeOptions options = dialog.getRunOptions();
EditorEventManager eventManager = EditorEventManagerBase.forEditor(editor);
if (eventManager != null) {
if (options.getTextRangeType() == TextRangeType.SELECTED_TEXT) {
eventManager.reformatSelection();
} else {
eventManager.reformat();
}
}
} else {
// if user chose cancel , the dialog in super.actionPerformed(e) will show again
// super.actionPerformed(e);
}
} else {
super.actionPerformed(e);
}
} else {
super.actionPerformed(e); super.actionPerformed(e);
return;
}
PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
if (psiFile == null) {
super.actionPerformed(e);
return;
}
VirtualFile virFile = FileDocumentManager.getInstance().getFile(editor.getDocument());
if (!IntellijLanguageClient.isExtensionSupported(virFile)) {
super.actionPerformed(e);
return;
}
boolean hasSelection = editor.getSelectionModel().hasSelection();
LayoutCodeDialog dialog = new LayoutCodeDialog(project, psiFile, hasSelection, HELP_ID);
dialog.show();
if (!dialog.isOK()) {
// if user chose cancel , the dialog in super.actionPerformed(e) will show again
// super.actionPerformed(e);
return;
}
LayoutCodeOptions options = dialog.getRunOptions();
EditorEventManager eventManager = EditorEventManagerBase.forEditor(editor);
if (eventManager != null) {
if (options.getTextRangeType() == TextRangeType.SELECTED_TEXT) {
eventManager.reformatSelection();
} else {
eventManager.reformat();
}
} }
} }

View file

@ -395,6 +395,7 @@ public class LanguageServerWrapper {
uriToEditorManagers.put(uri, set); uriToEditorManagers.put(uri, set);
manager.documentOpened(); manager.documentOpened();
} }
manager.initComplete();
LOG.info("Created a manager for " + uri); LOG.info("Created a manager for " + uri);
synchronized (toConnect) { synchronized (toConnect) {
toConnect.remove(editor); toConnect.remove(editor);

View file

@ -42,6 +42,7 @@ import com.intellij.refactoring.rename.RenamePsiElementProcessor;
import com.intellij.refactoring.rename.inplace.InplaceRefactoring; import com.intellij.refactoring.rename.inplace.InplaceRefactoring;
import com.intellij.refactoring.rename.inplace.MemberInplaceRenameHandler; import com.intellij.refactoring.rename.inplace.MemberInplaceRenameHandler;
import com.intellij.refactoring.rename.inplace.MemberInplaceRenamer; import com.intellij.refactoring.rename.inplace.MemberInplaceRenamer;
import lombok.val;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
@ -56,11 +57,14 @@ public class LSPRenameHandler implements RenameHandler {
@Override @Override
public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) { public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) {
val editor = dataContext.getData(CommonDataKeys.EDITOR);
if (editor == null)
return;
if (elements.length == 1) { if (elements.length == 1) {
new MemberInplaceRenameHandler() new MemberInplaceRenameHandler()
.doRename(elements[0], dataContext.getData(CommonDataKeys.EDITOR), dataContext); .doRename(elements[0], editor, dataContext);
} else { } else {
invoke(project, dataContext.getData(CommonDataKeys.EDITOR), dataContext.getData(CommonDataKeys.PSI_FILE), invoke(project, editor, dataContext.getData(CommonDataKeys.PSI_FILE),
dataContext); dataContext);
} }
} }

View file

@ -24,6 +24,7 @@ import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.event.DocumentListener; import com.intellij.openapi.editor.event.DocumentListener;
import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.util.io.FileUtilRt;
import lombok.val;
import org.eclipse.lsp4j.DidChangeTextDocumentParams; import org.eclipse.lsp4j.DidChangeTextDocumentParams;
import org.eclipse.lsp4j.DidCloseTextDocumentParams; import org.eclipse.lsp4j.DidCloseTextDocumentParams;
import org.eclipse.lsp4j.DidOpenTextDocumentParams; import org.eclipse.lsp4j.DidOpenTextDocumentParams;
@ -124,7 +125,10 @@ public class DocumentEventManager {
LOG.warn("trying to send open notification for document which was already opened!"); LOG.warn("trying to send open notification for document which was already opened!");
} else { } else {
openDocuments.add(document); openDocuments.add(document);
final String extension = FileUtilRt.getExtension(FileDocumentManager.getInstance().getFile(document).getName()); val theFile = FileDocumentManager.getInstance().getFile(document);
if (theFile == null)
return;
final String extension = FileUtilRt.getExtension(theFile.getName());
wrapper.getRequestManager().didOpen(new DidOpenTextDocumentParams(new TextDocumentItem(identifier.getUri(), wrapper.getRequestManager().didOpen(new DidOpenTextDocumentParams(new TextDocumentItem(identifier.getUri(),
wrapper.serverDefinition.languageIdFor(extension), wrapper.serverDefinition.languageIdFor(extension),
++version, ++version,

View file

@ -1463,6 +1463,9 @@ public class EditorEventManager {
}); });
} }
public void initComplete() {
}
private static class LSPTextEdit implements Comparable<LSPTextEdit> { private static class LSPTextEdit implements Comparable<LSPTextEdit> {
private String text; private String text;
private int startOffset; private int startOffset;

View file

@ -37,6 +37,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.refactoring.listeners.RefactoringElementListener; import com.intellij.refactoring.listeners.RefactoringElementListener;
import com.intellij.usageView.UsageInfo; import com.intellij.usageView.UsageInfo;
import lombok.val;
import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.ImmutablePair;
import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.ResourceOperation; import org.eclipse.lsp4j.ResourceOperation;
@ -76,19 +77,27 @@ public class WorkspaceEditHandler {
if (Stream.of(infos).allMatch(info -> info.getElement() instanceof LSPPsiElement)) { if (Stream.of(infos).allMatch(info -> info.getElement() instanceof LSPPsiElement)) {
Stream.of(infos).forEach(ui -> { Stream.of(infos).forEach(ui -> {
Editor editor = FileUtils.editorFromVirtualFile(ui.getVirtualFile(), ui.getProject()); Editor editor = FileUtils.editorFromVirtualFile(ui.getVirtualFile(), ui.getProject());
TextRange range = ui.getElement().getTextRange(); val element = ui.getElement();
if (element == null) {
return;
}
TextRange range = element.getTextRange();
Range lspRange = new Range(DocumentUtils.offsetToLSPPos(editor, range.getStartOffset()), Range lspRange = new Range(DocumentUtils.offsetToLSPPos(editor, range.getStartOffset()),
DocumentUtils.offsetToLSPPos(editor, range.getEndOffset())); DocumentUtils.offsetToLSPPos(editor, range.getEndOffset()));
TextEdit edit = new TextEdit(lspRange, newName); TextEdit edit = new TextEdit(lspRange, newName);
String uri = null; String uri = null;
blk:
try { try {
val vfs = ui.getVirtualFile();
if (vfs == null) {
break blk;
}
uri = FileUtil.sanitizeURI( uri = FileUtil.sanitizeURI(
new URL(ui.getVirtualFile().getUrl().replace(" ", FileUtil.SPACE_ENCODED)).toURI() new URL(vfs.getUrl().replace(" ", FileUtil.SPACE_ENCODED)).toURI().toString());
.toString());
} catch (MalformedURLException | URISyntaxException e) { } catch (MalformedURLException | URISyntaxException e) {
LOG.warn(e); LOG.warn(e);
} }
if (edits.keySet().contains(uri)) { if (edits.containsKey(uri)) {
edits.get(uri).add(edit); edits.get(uri).add(edit);
} else { } else {
List<TextEdit> textEdits = new ArrayList<>(); List<TextEdit> textEdits = new ArrayList<>();
@ -208,6 +217,8 @@ public class WorkspaceEditHandler {
} catch (URISyntaxException e) { } catch (URISyntaxException e) {
LOG.warn(e); LOG.warn(e);
} }
if (file == null)
return () -> {};
FileEditorManager fileEditorManager = FileEditorManager.getInstance(project); FileEditorManager fileEditorManager = FileEditorManager.getInstance(project);
OpenFileDescriptor descriptor = new OpenFileDescriptor(project, file); OpenFileDescriptor descriptor = new OpenFileDescriptor(project, file);
Editor editor = ApplicationUtil Editor editor = ApplicationUtil

View file

@ -116,16 +116,6 @@ public class FileUtils {
return null; return null;
} }
/**
* Returns a file type given an editor
*
* @param editor The editor
* @return The FileType
*/
public static FileType fileTypeFromEditor(Editor editor) {
return FileDocumentManager.getInstance().getFile(editor.getDocument()).getFileType();
}
/** /**
* Transforms an editor (Document) identifier to an LSP identifier * Transforms an editor (Document) identifier to an LSP identifier
* *

View file

@ -43,7 +43,11 @@ public abstract class ProfileStateBase<T extends ZigExecConfigBase<T>> extends C
@Override @Override
protected @NotNull ProcessHandler startProcess() throws ExecutionException { protected @NotNull ProcessHandler startProcess() throws ExecutionException {
return new ZigProcessHandler(getCommandLine(ProjectUtil.getToolchain(getEnvironment().getProject()), false)); val toolchain = ProjectUtil.getToolchain(getEnvironment().getProject());
if (toolchain == null) {
throw new ExecutionException("Failed to get zig toolchain from project");
}
return new ZigProcessHandler(getCommandLine(toolchain, false));
} }
public GeneralCommandLine getCommandLine(AbstractZigToolchain toolchain, boolean debug) throws ExecutionException { public GeneralCommandLine getCommandLine(AbstractZigToolchain toolchain, boolean debug) throws ExecutionException {

View file

@ -18,15 +18,16 @@ package com.falsepattern.zigbrains.zig.environment;
import lombok.Builder; import lombok.Builder;
import lombok.With; import lombok.With;
import org.jetbrains.annotations.Nullable;
@With @With
@Builder @Builder
public record ZLSConfig(String zig_exe_path, public record ZLSConfig(@Nullable String zig_exe_path,
String zig_lib_path, @Nullable String zig_lib_path,
Boolean enable_build_on_save, @Nullable Boolean enable_build_on_save,
String build_on_save_step, @Nullable String build_on_save_step,
Boolean dangerous_comptime_experiments_do_not_enable, @Nullable Boolean dangerous_comptime_experiments_do_not_enable,
Boolean highlight_global_var_declarations @Nullable Boolean highlight_global_var_declarations
) { ) {
} }

View file

@ -16,6 +16,7 @@
package com.falsepattern.zigbrains.zig.lsp; package com.falsepattern.zigbrains.zig.lsp;
import com.falsepattern.zigbrains.common.util.ApplicationUtil;
import com.falsepattern.zigbrains.lsp.client.languageserver.ServerOptions; import com.falsepattern.zigbrains.lsp.client.languageserver.ServerOptions;
import com.falsepattern.zigbrains.lsp.client.languageserver.requestmanager.RequestManager; import com.falsepattern.zigbrains.lsp.client.languageserver.requestmanager.RequestManager;
import com.falsepattern.zigbrains.lsp.client.languageserver.wrapper.LanguageServerWrapper; import com.falsepattern.zigbrains.lsp.client.languageserver.wrapper.LanguageServerWrapper;
@ -26,6 +27,7 @@ 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;
@ -111,6 +113,11 @@ public class ZLSEditorEventManager extends EditorEventManager {
return result; return result;
} }
@Override
public void initComplete() {
ApplicationUtil.pool(() -> HighlightingUtil.refreshHighlighting(this));
}
@Override @Override
public Runnable getEditsRunnable(int version, List<Either<TextEdit, InsertReplaceEdit>> edits, String name, boolean setCaret) { public Runnable getEditsRunnable(int version, List<Either<TextEdit, InsertReplaceEdit>> edits, String name, boolean setCaret) {
val run = super.getEditsRunnable(version, edits, name, setCaret); val run = super.getEditsRunnable(version, edits, name, setCaret);

View file

@ -16,6 +16,7 @@
package com.falsepattern.zigbrains.zig.lsp; package com.falsepattern.zigbrains.zig.lsp;
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;
@ -74,7 +75,7 @@ public class ZLSStartupActivity implements ProjectActivity {
try { try {
val tmpFile = Files.createTempFile("zigbrains-zls-autoconf", ".json"); val tmpFile = Files.createTempFile("zigbrains-zls-autoconf", ".json");
val config = ZLSConfigProvider.findEnvironment(project); val config = ZLSConfigProvider.findEnvironment(project);
if (config.zig_exe_path().isEmpty() && config.zig_lib_path().isEmpty()) { if (StringUtil.isEmpty(config.zig_exe_path()) && StringUtil.isEmpty(config.zig_lib_path())) {
Notifications.Bus.notify(new Notification("ZigBrains.ZLS", "(ZLS) Failed to detect zig path from project toolchain", NotificationType.WARNING)); Notifications.Bus.notify(new Notification("ZigBrains.ZLS", "(ZLS) Failed to detect zig path from project toolchain", NotificationType.WARNING));
configOK = false; configOK = false;
break blk; break blk;