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 21:10:47 +01:00
parent bdb45a375c
commit a0eb491f2c
Signed by: falsepattern
GPG key ID: E930CDEC50C50E23
14 changed files with 98 additions and 52 deletions

View file

@ -18,7 +18,13 @@ Changelog structure reference:
## [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

View file

@ -17,6 +17,7 @@
package com.falsepattern.zigbrains.common.util;
import lombok.val;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
@ -29,6 +30,9 @@ public class StringUtil {
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];

View file

@ -21,6 +21,7 @@ import com.falsepattern.zigbrains.debugger.dap.WrappedDebugServer;
import com.intellij.execution.ExecutionException;
import com.intellij.util.system.CpuArch;
import com.jetbrains.cidr.ArchitectureType;
import lombok.Cleanup;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
@ -112,7 +113,11 @@ public class WinDAPDriver extends DAPDriver<
val hasher = MessageDigest.getInstance("SHA-256");
hasher.update(handshake.getValue().getBytes(StandardCharsets.UTF_8));
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.finished();
var b = new byte[1];

View file

@ -46,14 +46,29 @@ public class LSPShowReformatDialogAction extends ShowReformatFileDialog implemen
Editor editor = e.getData(CommonDataKeys.EDITOR);
Project project = e.getData(CommonDataKeys.PROJECT);
if (editor != null && project != null) {
if (editor == null || project == null) {
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)) {
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 (!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) {
@ -63,16 +78,6 @@ public class LSPShowReformatDialogAction extends ShowReformatFileDialog implemen
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);
}
}
@Override

View file

@ -395,6 +395,7 @@ public class LanguageServerWrapper {
uriToEditorManagers.put(uri, set);
manager.documentOpened();
}
manager.initComplete();
LOG.info("Created a manager for " + uri);
synchronized (toConnect) {
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.MemberInplaceRenameHandler;
import com.intellij.refactoring.rename.inplace.MemberInplaceRenamer;
import lombok.val;
import org.jetbrains.annotations.NotNull;
import java.lang.ref.WeakReference;
@ -56,11 +57,14 @@ public class LSPRenameHandler implements RenameHandler {
@Override
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) {
new MemberInplaceRenameHandler()
.doRename(elements[0], dataContext.getData(CommonDataKeys.EDITOR), dataContext);
.doRename(elements[0], editor, dataContext);
} else {
invoke(project, dataContext.getData(CommonDataKeys.EDITOR), dataContext.getData(CommonDataKeys.PSI_FILE),
invoke(project, editor, dataContext.getData(CommonDataKeys.PSI_FILE),
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.fileEditor.FileDocumentManager;
import com.intellij.openapi.util.io.FileUtilRt;
import lombok.val;
import org.eclipse.lsp4j.DidChangeTextDocumentParams;
import org.eclipse.lsp4j.DidCloseTextDocumentParams;
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!");
} else {
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.serverDefinition.languageIdFor(extension),
++version,

View file

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

View file

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

View file

@ -116,16 +116,6 @@ public class FileUtils {
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
*

View file

@ -43,7 +43,11 @@ public abstract class ProfileStateBase<T extends ZigExecConfigBase<T>> extends C
@Override
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 {

View file

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

View file

@ -16,6 +16,7 @@
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.requestmanager.RequestManager;
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.TokenDecoder;
import com.intellij.lang.annotation.Annotation;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.event.DocumentListener;
import lombok.val;
@ -111,6 +113,11 @@ public class ZLSEditorEventManager extends EditorEventManager {
return result;
}
@Override
public void initComplete() {
ApplicationUtil.pool(() -> HighlightingUtil.refreshHighlighting(this));
}
@Override
public Runnable getEditsRunnable(int version, List<Either<TextEdit, InsertReplaceEdit>> edits, String name, boolean setCaret) {
val run = super.getEditsRunnable(version, edits, name, setCaret);

View file

@ -16,6 +16,7 @@
package com.falsepattern.zigbrains.zig.lsp;
import com.falsepattern.zigbrains.common.util.StringUtil;
import com.falsepattern.zigbrains.lsp.IntellijLanguageClient;
import com.falsepattern.zigbrains.lsp.utils.FileUtils;
import com.falsepattern.zigbrains.zig.environment.ZLSConfigProvider;
@ -74,7 +75,7 @@ public class ZLSStartupActivity implements ProjectActivity {
try {
val tmpFile = Files.createTempFile("zigbrains-zls-autoconf", ".json");
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));
configOK = false;
break blk;