diff --git a/CHANGELOG.md b/CHANGELOG.md index 66b4138..94cb945 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,6 @@ - Support for new EAP versions ### Changed -- HighlightProblemListener is now deprecated - MarkupModelListener is now the default listener ### Fixed diff --git a/src/main/java/org/overengineer/inlineproblems/DocumentMarkupModelScanner.java b/src/main/java/org/overengineer/inlineproblems/DocumentMarkupModelScanner.java index ea51e91..e100492 100644 --- a/src/main/java/org/overengineer/inlineproblems/DocumentMarkupModelScanner.java +++ b/src/main/java/org/overengineer/inlineproblems/DocumentMarkupModelScanner.java @@ -1,6 +1,7 @@ package org.overengineer.inlineproblems; import com.intellij.codeInsight.daemon.impl.HighlightInfo; +import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; @@ -10,7 +11,10 @@ import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.project.ProjectManager; +import com.intellij.openapi.util.Disposer; import com.intellij.util.concurrency.AppExecutorUtil; +import com.intellij.util.ui.update.MergingUpdateQueue; +import com.intellij.util.ui.update.Update; import org.overengineer.inlineproblems.entities.InlineProblem; import org.overengineer.inlineproblems.entities.enums.Listener; import org.overengineer.inlineproblems.listeners.HighlightProblemListener; @@ -23,7 +27,7 @@ import java.util.concurrent.TimeUnit; -public class DocumentMarkupModelScanner { +public class DocumentMarkupModelScanner implements Disposable { private final ProblemManager problemManager = ApplicationManager.getApplication().getService(ProblemManager.class); private final Logger logger = Logger.getInstance(DocumentMarkupModelScanner.class); @@ -32,18 +36,25 @@ public class DocumentMarkupModelScanner { private static DocumentMarkupModelScanner instance; + private final MergingUpdateQueue mergingUpdateQueue; + private ScheduledFuture scheduledFuture; public static final String NAME = "ManualScanner"; - public static DocumentMarkupModelScanner getInstance() { - if (instance == null) - instance = new DocumentMarkupModelScanner(); - - return instance; - } - private DocumentMarkupModelScanner() { + Disposer.register(problemManager, this); + + mergingUpdateQueue = new MergingUpdateQueue( + "DocumentMarkupModelScannerQueue", + 10, + true, + null, + this, + null, + true + ); + SettingsState settingsState = SettingsState.getInstance(); if (settingsState.getEnabledListener() == Listener.MANUAL_SCANNING) { delayMilliseconds = settingsState.getManualScannerDelay(); @@ -52,6 +63,18 @@ private DocumentMarkupModelScanner() { createAndStartScheduledFuture(); } + public static DocumentMarkupModelScanner getInstance() { + if (instance == null) + instance = new DocumentMarkupModelScanner(); + + return instance; + } + + @Override + public void dispose() { + mergingUpdateQueue.cancelAllUpdates(); + } + public void scanForProblemsManually() { ProjectManager projectManager = ProjectManager.getInstanceIfCreated(); @@ -78,18 +101,27 @@ public void scanForProblemsManually() { } } + /** + * This function is queued in the mergingUpdateQueue because it is called frequently, this can be multiple times per + * millisecond if the HighlightProblemListener is used. + */ public void scanForProblemsManuallyInTextEditor(TextEditor textEditor) { if (textEditor.getFile() == null) { return; } - List problems = getProblemsInEditor(textEditor); + mergingUpdateQueue.queue(new Update("scan") { + @Override + public void run() { + List problems = getProblemsInEditor(textEditor); - problemManager.updateFromNewActiveProblemsForProjectAndFile( - problems, - textEditor.getEditor().getProject(), - textEditor.getFile().getPath() - ); + problemManager.updateFromNewActiveProblemsForProjectAndFile( + problems, + textEditor.getEditor().getProject(), + textEditor.getFile().getPath() + ); + } + }); } private List getProblemsInEditor(TextEditor textEditor) { diff --git a/src/main/java/org/overengineer/inlineproblems/listeners/HighlightProblemListener.java b/src/main/java/org/overengineer/inlineproblems/listeners/HighlightProblemListener.java index b3d7f15..6e92b60 100644 --- a/src/main/java/org/overengineer/inlineproblems/listeners/HighlightProblemListener.java +++ b/src/main/java/org/overengineer/inlineproblems/listeners/HighlightProblemListener.java @@ -17,7 +17,7 @@ public class HighlightProblemListener implements HighlightInfoFilter { private final DocumentMarkupModelScanner markupModelScanner = DocumentMarkupModelScanner.getInstance(); private final SettingsState settingsState = SettingsState.getInstance(); - public static final String NAME = "HighlightProblemListener (Deprecated)"; + public static final String NAME = "HighlightProblemListener"; public static final int ADDITIONAL_MANUAL_SCAN_DELAY_MILLIS = 2000; @Override @@ -28,9 +28,6 @@ public boolean accept(@NotNull HighlightInfo highlightInfo, @Nullable PsiFile fi if (file == null || !file.isValid()) return true; - // The HighlightProblemListener is deprecated because the accept function is called a lot of times per second - // and the invokeLater queues the invocations, so this is often called before handleAccept is finished. - // invokeAndWait also doesn't work because it can cause a deadlock. if (!file.getProject().isDisposed()) { ApplicationManager.getApplication().invokeLater(() -> handleAccept(file)); } diff --git a/src/main/java/org/overengineer/inlineproblems/listeners/MarkupModelProblemListener.java b/src/main/java/org/overengineer/inlineproblems/listeners/MarkupModelProblemListener.java index b8ae1c1..5b0c646 100644 --- a/src/main/java/org/overengineer/inlineproblems/listeners/MarkupModelProblemListener.java +++ b/src/main/java/org/overengineer/inlineproblems/listeners/MarkupModelProblemListener.java @@ -30,7 +30,7 @@ public class MarkupModelProblemListener implements MarkupModelListener { private static final List disposables = new ArrayList<>(); - public static final String NAME = "MarkupModelListener"; + public static final String NAME = "MarkupModelListener (default)"; private enum EventType { ADD, REMOVE, CHANGE diff --git a/src/main/java/org/overengineer/inlineproblems/settings/SettingsComponent.java b/src/main/java/org/overengineer/inlineproblems/settings/SettingsComponent.java index 0f327fb..894cf3d 100644 --- a/src/main/java/org/overengineer/inlineproblems/settings/SettingsComponent.java +++ b/src/main/java/org/overengineer/inlineproblems/settings/SettingsComponent.java @@ -136,10 +136,10 @@ public SettingsComponent() { .addSeparator() .addComponent(new JBLabel("General")) .addLabeledComponent(new JBLabel("Enabled problem listener"), enabledListener) - .addTooltip("- MarkupModelListener: Called after addition of a RangeHighlighter to a file. Faster on large files, slower on small ones") - .addTooltip("- ManualScanner: Scans the DocumentMarkupModel for all highlighters at a fixed delay") - .addTooltip("- HighlightProblemListener (DEPRECATED): Faster on small to medium sized files, slower on large ones.") - .addTooltip(" Called way to often and can cause freezes. If you want similar performance use the ManualScanner instead") + .addTooltip("- MarkupModelListener (default): Called after addition of a RangeHighlighter to a file. Faster on large files, slower on small ones") + .addTooltip("- HighlightProblemListener: Faster on small to medium sized files, slower on large ones. Called very often and can cause slowdowns.") + .addTooltip("- ManualScanner: Scans the DocumentMarkupModel for all highlighters at a fixed delay, uses the same logic ") + .addTooltip(" as HighlightProblemListener but can help with slowdowns on big files.") .addLabeledComponent(new JBLabel("ManualScanner delay in milliseconds"), manualScannerDelay) .addTooltip("Delay between manual scans, only used when ManualScanner is enabled") .addComponent(forceErrorsInSameLine, 0)