diff --git a/src/main/java/org/asciidoc/intellij/AsciiDocWrapper.java b/src/main/java/org/asciidoc/intellij/AsciiDocWrapper.java index 420a59cc4..441f821a8 100644 --- a/src/main/java/org/asciidoc/intellij/AsciiDocWrapper.java +++ b/src/main/java/org/asciidoc/intellij/AsciiDocWrapper.java @@ -235,6 +235,9 @@ public static void beforePluginUnload() { } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) { LOG.error("unable to de-register shutdown hook", e); } + attributesRetriever = null; + antoraIncludeAdapter = null; + prependConfig = null; System.gc(); // still, this is not enough; there are dangling ThreadLocals like "org.jruby.Ruby$FStringEqual" // in addition to that: classes are marked at "Held by JVM" and not unloaded. Reason is unknown, maybe diff --git a/src/main/java/org/asciidoc/intellij/activities/AsciiDocHandleUnloadActivity.java b/src/main/java/org/asciidoc/intellij/activities/AsciiDocHandleUnloadActivity.java index ad5d49d0c..b1c1375f2 100644 --- a/src/main/java/org/asciidoc/intellij/activities/AsciiDocHandleUnloadActivity.java +++ b/src/main/java/org/asciidoc/intellij/activities/AsciiDocHandleUnloadActivity.java @@ -1,20 +1,30 @@ package org.asciidoc.intellij.activities; +import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; +import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl; +import com.intellij.codeInsight.daemon.impl.DaemonProgressIndicator; import com.intellij.ide.lightEdit.LightEditCompatible; import com.intellij.ide.plugins.CannotUnloadPluginException; import com.intellij.ide.plugins.DynamicPluginListener; import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.startup.StartupActivity; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.messages.MessageBusConnection; import org.asciidoc.intellij.AsciiDocPlugin; import org.asciidoc.intellij.AsciiDocWrapper; +import org.asciidoc.intellij.editor.AsciiDocSplitEditor; import org.jetbrains.annotations.NotNull; +import java.lang.reflect.Field; +import java.util.Map; import java.util.Objects; /** @@ -56,7 +66,7 @@ public void checkUnloadPlugin(@NotNull IdeaPluginDescriptor pluginDescriptor) th // before trying to re-enable this for internal mode, try to unload plugin in development mode and analyze heap dumps. // if (!ApplicationManager.getApplication().isInternal()) { - throw new CannotUnloadPluginException("unloading mechanism is not safe, incomplete unloading might lead to strange exceptions"); + throw new CannotUnloadPluginException("unloading mechanism is not safe, incomplete unloading might lead to strange exceptions"); // } // found that "IdeScriptEngineManagerImpl" will hold a reference to "org.jruby.embed.jsr223.JRubyEngineFactory" // https://youtrack.jetbrains.com/issue/IDEA-285933 @@ -69,6 +79,38 @@ public void beforePluginUnload(@NotNull IdeaPluginDescriptor pluginDescriptor, b if (Objects.equals(pluginDescriptor.getPluginId().getIdString(), AsciiDocPlugin.PLUGIN_ID)) { LOG.info("beforePluginUnload"); AsciiDocWrapper.beforePluginUnload(); + for (Project project : ProjectManager.getInstance().getOpenProjects()) { + + // Workaround for https://youtrack.jetbrains.com/issue/IJPL-18535/ + try { + DaemonCodeAnalyzer dca = DaemonCodeAnalyzer.getInstance(project); + Field myUpdateProgress = DaemonCodeAnalyzerImpl.class.getDeclaredField("myUpdateProgress"); + myUpdateProgress.setAccessible(true); + Map map = (Map) myUpdateProgress.get(dca); + map.entrySet().clear(); + } catch (NoSuchFieldException | IllegalAccessException e) { + // nopp + } + + // Possibly not necessary in the future if IntelliJ doesn't hold on to references + FileEditorManager fem = FileEditorManager.getInstance(project); + for (FileEditor editor : fem.getAllEditors()) { + if ((editor instanceof AsciiDocSplitEditor)) { + ApplicationManager.getApplication().runReadAction(() -> { + VirtualFile vFile = editor.getFile(); + if (vFile != null && vFile.isValid()) { + // an AsciiDoc file in a non-split editor, close and re-open the file to enforce split editor + ApplicationManager.getApplication().runWriteAction(() -> { + // closing the file might trigger a save, therefore, wrap in write action + if (!project.isDisposed()) { + fem.closeFile(vFile); + } + }); + } + }); + } + } + } busConnection.dispose(); } } diff --git a/src/main/java/org/asciidoc/intellij/editor/AsciiDocPreviewEditor.java b/src/main/java/org/asciidoc/intellij/editor/AsciiDocPreviewEditor.java index de4caab41..321a883d5 100644 --- a/src/main/java/org/asciidoc/intellij/editor/AsciiDocPreviewEditor.java +++ b/src/main/java/org/asciidoc/intellij/editor/AsciiDocPreviewEditor.java @@ -74,6 +74,7 @@ import java.beans.PropertyChangeListener; import java.io.File; import java.nio.file.Path; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -693,7 +694,11 @@ public StructureViewBuilder getStructureViewBuilder() { public void dispose() { if (myPanel != null) { Disposer.dispose(myPanel); + synchronized (this) { + myPanel = detachOldPanelAndCreateAndAttachNewOne(document, tempImagesPath, myHtmlPanelWrapper, hint, myPanel, null, AsciiDocPreviewEditor.this::forceRefresh); + } } + Arrays.stream(myHtmlPanelWrapper.getComponentListeners()).forEach(l -> myHtmlPanelWrapper.removeComponentListener(l)); AsciiDocWrapper.cleanupImagesPath(tempImagesPath); } diff --git a/src/main/java/org/asciidoc/intellij/editor/jcef/AsciiDocJCEFHtmlPanel.java b/src/main/java/org/asciidoc/intellij/editor/jcef/AsciiDocJCEFHtmlPanel.java index f4cba5770..9f8ee7804 100644 --- a/src/main/java/org/asciidoc/intellij/editor/jcef/AsciiDocJCEFHtmlPanel.java +++ b/src/main/java/org/asciidoc/intellij/editor/jcef/AsciiDocJCEFHtmlPanel.java @@ -395,30 +395,39 @@ private void registerHandlers() { private void disposeHandlers() { if (myJSQuerySetScrollY != null) { + myJSQuerySetScrollY.clearHandlers(); Disposer.dispose(myJSQuerySetScrollY); } if (myRenderedIteration != null) { + myRenderedIteration.clearHandlers(); Disposer.dispose(myRenderedIteration); } if (myRenderedResult != null) { + myRenderedResult.clearHandlers(); Disposer.dispose(myRenderedResult); } if (myBrowserLog != null) { + myBrowserLog.clearHandlers(); Disposer.dispose(myBrowserLog); } if (myScrollEditorToLine != null) { + myScrollEditorToLine.clearHandlers(); Disposer.dispose(myScrollEditorToLine); } if (myZoomDelta != null) { + myZoomDelta.clearHandlers(); Disposer.dispose(myZoomDelta); } if (myZoomReset != null) { + myZoomReset.clearHandlers(); Disposer.dispose(myZoomReset); } if (mySaveImage != null) { + mySaveImage.clearHandlers(); Disposer.dispose(mySaveImage); } if (myOpenLink != null) { + myOpenLink.clearHandlers(); Disposer.dispose(myOpenLink); } } diff --git a/src/main/java/org/asciidoc/intellij/ui/SplitFileEditor.java b/src/main/java/org/asciidoc/intellij/ui/SplitFileEditor.java index d2d95ac26..30aef6c5d 100644 --- a/src/main/java/org/asciidoc/intellij/ui/SplitFileEditor.java +++ b/src/main/java/org/asciidoc/intellij/ui/SplitFileEditor.java @@ -277,6 +277,7 @@ public StructureViewBuilder getStructureViewBuilder() { @Override public void dispose() { + myComponent.removeAll(); Disposer.dispose(myMainEditor); Disposer.dispose(mySecondEditor); }