izhangzhihao / intellij-rainbow-brackets

🌈Rainbow Brackets for IntelliJ based IDEs/Android Studio/HUAWEI DevEco Studio/Fleet
https://plugins.jetbrains.com/plugin/10080-rainbow-brackets
GNU General Public License v3.0
4.35k stars 202 forks source link

SlowOperation assertion in paintCustomRenderers #2673

Closed gregsh closed 7 months ago

gregsh commented 7 months ago

Hi from JetBrains!

We are moving all PSI/VFS/Index/ProjectModel-related work off the UI thread using SlowOperation.assertSlowOperationsAreAllowed. All that "heavy" stuff on EDT leads to UI freezes.

Here's what we got in RainbowIndentGuideRenderer. All that PSI logic must now go to RainbowIndentsPass.doCollectInformation which is called on the background thread. Please let us know if you have questions on how to do that.

java.lang.Throwable: Slow operations are prohibited on EDT. See SlowOperations.assertSlowOperationsAreAllowed javadoc.
    at com.intellij.openapi.diagnostic.Logger.error(Logger.java:366)
    at com.intellij.util.SlowOperations.assertSlowOperationsAreAllowed(SlowOperations.java:130)
    at com.intellij.workspaceModel.core.fileIndex.impl.WorkspaceFileIndexDataImpl.ensureIsUpToDate(WorkspaceFileIndexDataImpl.kt:129)
    at com.intellij.workspaceModel.core.fileIndex.impl.WorkspaceFileIndexDataImpl.getFileInfo(WorkspaceFileIndexDataImpl.kt:75)
    at com.intellij.workspaceModel.core.fileIndex.impl.WorkspaceFileIndexImpl.getFileInfo(WorkspaceFileIndexImpl.kt:220)
    at com.intellij.openapi.roots.impl.ProjectFileIndexImpl.isUnderIgnored(ProjectFileIndexImpl.java:99)
    at com.intellij.openapi.roots.impl.ProjectFileIndexFacade.isUnderIgnored(ProjectFileIndexFacade.java:66)
    at com.intellij.psi.impl.file.impl.FileManagerImpl.isExcludedOrIgnored(FileManagerImpl.java:425)
    at com.intellij.psi.impl.file.impl.FileManagerImpl.findDirectoryImpl(FileManagerImpl.java:411)
    at com.intellij.psi.impl.file.impl.FileManagerImpl.findDirectoryImpl(FileManagerImpl.java:415)
    at com.intellij.psi.impl.file.impl.FileManagerImpl.findDirectoryImpl(FileManagerImpl.java:415)
    at com.intellij.psi.impl.file.impl.FileManagerImpl.findDirectoryImpl(FileManagerImpl.java:415)
    at com.intellij.psi.impl.file.impl.FileManagerImpl.findDirectoryImpl(FileManagerImpl.java:415)
    at com.intellij.psi.impl.file.impl.FileManagerImpl.findDirectoryImpl(FileManagerImpl.java:415)
    at com.intellij.psi.impl.file.impl.FileManagerImpl.findDirectory(FileManagerImpl.java:403)
    at com.intellij.psi.impl.PsiManagerImpl.findDirectory(PsiManagerImpl.java:169)
    at com.intellij.psi.AbstractFileViewProvider.shouldCreatePsi(AbstractFileViewProvider.java:90)
    at com.intellij.psi.SingleRootFileViewProvider.createFile(SingleRootFileViewProvider.java:149)
    at com.intellij.psi.SingleRootFileViewProvider.getPsiInner(SingleRootFileViewProvider.java:105)
    at com.intellij.psi.AbstractFileViewProvider.getPsi(AbstractFileViewProvider.java:196)
    at com.intellij.psi.impl.file.impl.FileManagerImpl.areViewProvidersEquivalent(FileManagerImpl.java:542)
    at com.intellij.psi.impl.file.impl.FileManagerImpl.shouldResurrect(FileManagerImpl.java:639)
    at com.intellij.psi.impl.file.impl.FileManagerImpl.evaluateValidity(FileManagerImpl.java:607)
    at com.intellij.psi.impl.file.impl.FileManagerImpl.findCachedViewProvider(FileManagerImpl.java:225)
    at com.intellij.psi.impl.file.impl.FileManagerImpl.findViewProvider(FileManagerImpl.java:182)
    at com.intellij.psi.impl.file.impl.FileManagerImpl.findFile(FileManagerImpl.java:362)
    at com.intellij.psi.impl.PsiManagerImpl.findFile(PsiManagerImpl.java:156)
    at x$a.a(Unknown Source)
    at x$a.a(Unknown Source)
    at x.paint(Unknown Source)
    at com.intellij.openapi.editor.impl.view.EditorPainter$Session.lambda$paintCustomRenderers$2(EditorPainter.java:592)
    at com.intellij.openapi.editor.impl.MarkupModelImpl.processRangeHighlightersOverlappingWith(MarkupModelImpl.java:301)
    at com.intellij.openapi.editor.impl.view.EditorPainter$Session.paintCustomRenderers(EditorPainter.java:584)
    at com.intellij.openapi.editor.impl.view.EditorPainter$Session.paint(EditorPainter.java:189)
    at com.intellij.openapi.editor.impl.view.EditorPainter.paint(EditorPainter.java:71)
    at com.intellij.openapi.editor.impl.view.EditorView.paint(EditorView.java:280)
    at com.intellij.openapi.editor.impl.EditorImpl.lambda$paint$25(EditorImpl.java:1966)
    at com.intellij.openapi.application.ReadAction.lambda$run$1(ReadAction.java:60)
    at com.intellij.openapi.application.impl.ApplicationImpl.runReadAction(ApplicationImpl.java:920)
    at com.intellij.openapi.application.ReadAction.compute(ReadAction.java:69)
    at com.intellij.openapi.application.ReadAction.run(ReadAction.java:59)
    at com.intellij.openapi.editor.impl.EditorImpl.paint(EditorImpl.java:1941)
    at com.intellij.openapi.editor.impl.EditorComponentImpl.paintComponent(EditorComponentImpl.java:278)
    at java.desktop/javax.swing.JComponent.paint(JComponent.java:1115)
    at com.intellij.openapi.editor.impl.EditorComponentImpl.paint(EditorComponentImpl.java:143)
    at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:955)
    at java.desktop/javax.swing.JComponent.paint(JComponent.java:1124)
    at java.desktop/javax.swing.JViewport.paint(JViewport.java:736)
    at com.intellij.ui.components.JBViewport.paint(JBViewport.java:237)
    at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:955)
    at java.desktop/javax.swing.JComponent.paint(JComponent.java:1124)
    at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:955)
    at java.desktop/javax.swing.JComponent.paint(JComponent.java:1124)
    at java.desktop/javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
    at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:955)
    at java.desktop/javax.swing.JComponent.paint(JComponent.java:1124)
    at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:955)
    at java.desktop/javax.swing.JComponent.paint(JComponent.java:1124)
    at java.desktop/javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
    at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:955)
    at java.desktop/javax.swing.JComponent.paint(JComponent.java:1124)
    at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:955)
    at java.desktop/javax.swing.JComponent.paint(JComponent.java:1124)
    at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:955)
    at java.desktop/javax.swing.JComponent.paint(JComponent.java:1124)
    at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:955)
    at java.desktop/javax.swing.JComponent.paint(JComponent.java:1124)
    at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:955)
    at com.intellij.openapi.fileEditor.impl.EditorTabs.paintChildren(EditorTabbedContainer.kt:604)
    at java.desktop/javax.swing.JComponent.paint(JComponent.java:1124)
    at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:955)
    at java.desktop/javax.swing.JComponent.paint(JComponent.java:1124)
    at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:955)
    at java.desktop/javax.swing.JComponent.paint(JComponent.java:1124)
    at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:955)
    at java.desktop/javax.swing.JComponent.paint(JComponent.java:1124)
    at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:955)
    at java.desktop/javax.swing.JComponent.paint(JComponent.java:1124)
    at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:955)
    at java.desktop/javax.swing.JComponent.paint(JComponent.java:1124)
    at java.desktop/javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
    at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:955)
    at java.desktop/javax.swing.JComponent.paint(JComponent.java:1124)
    at java.desktop/javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
    at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:955)
    at java.desktop/javax.swing.JComponent.paint(JComponent.java:1124)
    at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:955)
    at java.desktop/javax.swing.JComponent.paint(JComponent.java:1124)
    at java.desktop/javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
    at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:955)
    at java.desktop/javax.swing.JComponent.paintToOffscreen(JComponent.java:5319)
    at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBufferedFPScales(RepaintManager.java:1732)
    at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1641)
    at java.desktop/javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1580)
    at java.desktop/javax.swing.RepaintManager.paint(RepaintManager.java:1347)
    at java.desktop/javax.swing.JComponent.paint(JComponent.java:1101)
    at java.desktop/java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:39)
    at java.desktop/sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:75)
    at java.desktop/sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:112)
    at java.desktop/java.awt.Container.paint(Container.java:2005)
    at java.desktop/java.awt.Window.paint(Window.java:3987)
    at com.intellij.openapi.wm.impl.IdeFrameImpl.paint(IdeFrameImpl.kt:89)
    at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:893)
    at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:865)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
    at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:865)
    at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:838)
    at java.desktop/javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:787)
    at java.desktop/javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1909)
    at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:789)
    at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:740)
    at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:734)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:759)
    at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.kt:668)
    at com.intellij.ide.IdeEventQueue._dispatchEvent$lambda$8(IdeEventQueue.kt:572)
    at com.intellij.openapi.application.impl.ApplicationImpl.withoutImplicitRead(ApplicationImpl.java:1480)
    at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.kt:572)
    at com.intellij.ide.IdeEventQueue.access$_dispatchEvent(IdeEventQueue.kt:68)
    at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1$1.compute(IdeEventQueue.kt:352)
    at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1$1.compute(IdeEventQueue.kt:351)
    at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:787)
    at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1.invoke(IdeEventQueue.kt:351)
    at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1.invoke(IdeEventQueue.kt:346)
    at com.intellij.ide.IdeEventQueueKt.performActivity$lambda$1(IdeEventQueue.kt:996)
    at com.intellij.openapi.application.TransactionGuardImpl.performActivity(TransactionGuardImpl.java:105)
    at com.intellij.ide.IdeEventQueueKt.performActivity(IdeEventQueue.kt:996)
    at com.intellij.ide.IdeEventQueue.dispatchEvent$lambda$5(IdeEventQueue.kt:346)
    at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.kt:383)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:207)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:92)
izhangzhihao commented 7 months ago

Thanks for informing me of this, I have some questions:

Which version of this plugin and IDE are you using? How can I reproduce this error? How can we define the '"heavy" stuff on EDT'?

izhangzhihao commented 7 months ago

I also have something like this IndentsModelCaretListener that triggered "Slow operations are prohibited on EDT", how can I fix this? any example?

gregsh commented 7 months ago

Which version of this plugin and IDE are you using?

Any 233.xxx. The latest IDEA 2023.3 EAP build will do. And the latest plugin version.

How can I reproduce this error?

The code does trigger the exception. That's clear to me when I read RainbowIndentGuideRenderer.

I'm not a user of the plugin. I just see lots of new reports in our Exception Analyzer tool.

How can we define the '"heavy" stuff on EDT'?

If you have the IDEA Community sources as SDK, you can find all the usages of the SlowOperations#assertSlowOperationsAreAllowed method.

The main idea is to eradicate UI freezes on the architectural level. So Disk/Network IO, PSI, VFS, Project Model, and some native calls are considered heavy. Anything that can block the UI thread. The UI thread (EDT) is only for managing and rendering Swing components and handling user events.

I also have something like this IndentsModelCaretListener that triggered "Slow operations are prohibited on EDT", how can I fix this? any example?

To fix for RainbowIndentGuideRenderer, we have to move the PSI (the PsiManager.findFile call) back to the RainbowIndentsPass.doCollectInformation because the latter is called on the background thread (BGT).

For the IndentsModelCaretListener... I need to see the error stacktrace first.

izhangzhihao commented 7 months ago

I guess I had to add SlowOperations.allowSlowOperations when calling caretPositionChanged

Update, it seems not to work as expected:

the modified code:

abstract class AbstractScopeHighlightingAction : CaretListener {

final override fun caretPositionChanged(e: CaretEvent) {
         e.editor.let { editor ->
             SlowOperations.allowSlowOperations(ThrowableRunnable { highlight(editor) })
         }
     }

}

the logs:

java.lang.Throwable: Slow operations are prohibited on EDT. See SlowOperations.assertSlowOperationsAreAllowed javadoc.
    at com.intellij.openapi.diagnostic.Logger.error(Logger.java:376)
    at com.intellij.util.SlowOperations.assertSlowOperationsAreAllowed(SlowOperations.java:95)
    at com.intellij.workspaceModel.core.fileIndex.impl.WorkspaceFileIndexDataImpl.ensureIsUpToDate(WorkspaceFileIndexDataImpl.kt:130)
    at com.intellij.workspaceModel.core.fileIndex.impl.WorkspaceFileIndexDataImpl.getFileInfo(WorkspaceFileIndexDataImpl.kt:75)
    at com.intellij.workspaceModel.core.fileIndex.impl.WorkspaceFileIndexImpl.getFileInfo(WorkspaceFileIndexImpl.kt:247)
    at com.intellij.openapi.roots.impl.ProjectFileIndexImpl.isUnderIgnored(ProjectFileIndexImpl.java:73)
    at com.intellij.openapi.roots.impl.ProjectFileIndexFacade.isUnderIgnored(ProjectFileIndexFacade.java:71)
    at com.intellij.psi.impl.file.impl.FileManagerImpl.isExcludedOrIgnored(FileManagerImpl.java:418)
    at com.intellij.psi.impl.file.impl.FileManagerImpl.findDirectoryImpl(FileManagerImpl.java:404)
    at com.intellij.psi.impl.file.impl.FileManagerImpl.findDirectory(FileManagerImpl.java:397)
    at com.intellij.psi.impl.PsiManagerImpl.findDirectory(PsiManagerImpl.java:173)
    at com.intellij.psi.impl.file.PsiDirectoryImpl.processChildren(PsiDirectoryImpl.java:190)
    at com.intellij.psi.impl.file.PsiDirectoryImpl.getChildren(PsiDirectoryImpl.java:205)
    at com.intellij.psi.impl.PsiElementBase.getFirstChild(PsiElementBase.java:33)
    at com.github.izhangzhihao.rainbow.brackets.action.AbstractScopeHighlightingAction$Companion.findPyElement(Unknown Source)
    at com.github.izhangzhihao.rainbow.brackets.action.AbstractScopeHighlightingAction$Companion.findRainbowInfoAt(Unknown Source)
    at com.github.izhangzhihao.rainbow.brackets.action.AbstractScopeHighlightingAction$Companion.access$findRainbowInfoAt(Unknown Source)
    at com.github.izhangzhihao.rainbow.brackets.action.AbstractScopeHighlightingAction.highlight(Unknown Source)
    at com.github.izhangzhihao.rainbow.brackets.action.AbstractScopeHighlightingAction.caretPositionChanged$lambda$2$lambda$1(Unknown Source)
    at com.intellij.util.SlowOperations.allowSlowOperations(SlowOperations.java:200)
    at com.github.izhangzhihao.rainbow.brackets.action.AbstractScopeHighlightingAction.caretPositionChanged(Unknown Source)
    at jdk.internal.reflect.GeneratedMethodAccessor178.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at com.intellij.util.EventDispatcher.dispatchVoidMethod(EventDispatcher.java:119)
    at com.intellij.util.EventDispatcher.lambda$createMulticaster$1(EventDispatcher.java:84)
    at jdk.proxy1/jdk.proxy1.$Proxy118.caretPositionChanged(Unknown Source)
    at jdk.internal.reflect.GeneratedMethodAccessor178.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at com.intellij.util.EventDispatcher.dispatchVoidMethod(EventDispatcher.java:119)
    at com.intellij.util.EventDispatcher.lambda$createMulticaster$1(EventDispatcher.java:84)
    at jdk.proxy1/jdk.proxy1.$Proxy118.caretPositionChanged(Unknown Source)
    at com.intellij.openapi.editor.impl.CaretModelImpl.fireCaretPositionChanged(CaretModelImpl.java:534)
    at com.intellij.openapi.editor.impl.CaretImpl.doMoveToLogicalPosition(CaretImpl.java:466)
    at com.intellij.openapi.editor.impl.CaretImpl.moveToLogicalPosition(CaretImpl.java:613)
    at com.intellij.openapi.editor.impl.CaretImpl.lambda$moveToLogicalPosition$2(CaretImpl.java:323)
    at com.intellij.openapi.editor.impl.CaretModelImpl.doWithCaretMerging(CaretModelImpl.java:406)
    at com.intellij.openapi.editor.impl.CaretImpl.moveToLogicalPosition(CaretImpl.java:323)
    at com.intellij.openapi.editor.impl.FoldingModelImpl.lambda$onFoldProcessingEnd$2(FoldingModelImpl.java:522)
    at com.intellij.openapi.editor.impl.CaretModelImpl.doWithCaretMerging(CaretModelImpl.java:411)
    at com.intellij.openapi.editor.impl.CaretModelImpl.runBatchCaretOperation(CaretModelImpl.java:327)
    at com.intellij.openapi.editor.impl.FoldingModelImpl.onFoldProcessingEnd(FoldingModelImpl.java:495)
    at com.intellij.openapi.editor.impl.FoldingModelImpl.runBatchFoldingOperation(FoldingModelImpl.java:299)
    at com.intellij.openapi.editor.impl.FoldingModelImpl.runBatchFoldingOperation(FoldingModelImpl.java:234)
    at com.intellij.openapi.editor.impl.EditorImpl.processMouseReleased(EditorImpl.java:2410)
    at com.intellij.openapi.editor.impl.EditorImpl$MyMouseAdapter.lambda$runMouseReleasedCommand$1(EditorImpl.java:4121)
    at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:224)
    at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:176)
    at com.intellij.openapi.editor.impl.EditorImpl$MyMouseAdapter.runMouseReleasedCommand(EditorImpl.java:4123)
    at com.intellij.openapi.editor.impl.EditorImpl$MyMouseAdapter.mouseReleased(EditorImpl.java:4008)
    at java.desktop/java.awt.Component.processMouseEvent(Component.java:6657)
    at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3385)
    at java.desktop/java.awt.Component.processEvent(Component.java:6422)
    at java.desktop/java.awt.Container.processEvent(Container.java:2266)
    at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5027)
    at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2324)
    at java.desktop/java.awt.Component.dispatchEvent(Component.java:4855)
    at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4969)
    at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4583)
    at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4524)
    at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2310)
    at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2809)
    at java.desktop/java.awt.Component.dispatchEvent(Component.java:4855)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:794)
    at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:739)
    at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:733)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:97)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:766)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:764)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:763)
    at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.kt:687)
    at com.intellij.ide.IdeEventQueue.dispatchMouseEvent(IdeEventQueue.kt:634)
    at com.intellij.ide.IdeEventQueue._dispatchEvent$lambda$10(IdeEventQueue.kt:579)
    at com.intellij.openapi.application.impl.RwLockHolder.runWithEnabledImplicitRead(RwLockHolder.kt:75)
    at com.intellij.openapi.application.impl.RwLockHolder.runWithImplicitRead(RwLockHolder.kt:67)
    at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.kt:579)
    at com.intellij.ide.IdeEventQueue.access$_dispatchEvent(IdeEventQueue.kt:71)
    at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1$1.compute(IdeEventQueue.kt:354)
    at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1$1.compute(IdeEventQueue.kt:353)
    at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:793)
    at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1.invoke(IdeEventQueue.kt:353)
    at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1.invoke(IdeEventQueue.kt:348)
    at com.intellij.ide.IdeEventQueueKt.performActivity$lambda$1(IdeEventQueue.kt:1006)
    at com.intellij.openapi.application.TransactionGuardImpl.performActivity(TransactionGuardImpl.java:114)
    at com.intellij.ide.IdeEventQueueKt.performActivity(IdeEventQueue.kt:1006)
    at com.intellij.ide.IdeEventQueue.dispatchEvent$lambda$7(IdeEventQueue.kt:348)
    at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:851)
    at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.kt:390)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:207)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:92)
gregsh commented 7 months ago

SlowOperations.allowSlowOperations was an old compatibility mode that is now being dropped. Slow operations are freezes in disguise, so they are not really allowed.

izhangzhihao commented 7 months ago

So I had to useApplication.runWriteAction() when doing highlighting.

gregsh commented 7 months ago

I hope you are joking because write-action (WA) is a very heavy and disruptive operation. It is simply unacceptable performance-wise. The caret would noticeably freeze all the time.

The solution is conceptually simple - we need to employ an asynchronous approach and calculate what's needed on a background thread (BGT). I see two ways regarding EDT-BGT thread management: auto and manual.

  1. (auto) HighlightingPass - will be a bit slower than needed due to all highlighting engine machinery
  2. (manual) BackgroundHighlighter#registerListeners/submitIdentifierHighlighterPass (uses NonBlockingReadAction)

I think, for perceived performance, option 2 is best for you. See BackgroundHighlighter:70 for similar caret listener.

BackgroundHighlighter does the matched brace highlighting in all IntelliJ IDEs. Rainbow brackets will get the same performance and non-freezing, non-slow-operations-in-edt features.

izhangzhihao commented 7 months ago

We are talking about this case:

abstract class AbstractScopeHighlightingAction : CaretListener {
    final override fun caretPositionChanged(e: CaretEvent) {
         e.editor.let { editor ->
             ApplicationManager.getApplication().runWriteAction {
                highlight(editor)
            }
         }
    }
}

When I do highlighting, it is not a read action(said by the IDE), so the BackgroundHighlighter could not be used in this case.

gregsh commented 7 months ago

Brace-matching highlighter has the same functionality as rainbow brackets. Same caret listener. Similar goals. If it works for brace-matching, it works for rainbow brackets.

UPD Here's the code snippet from BackgroundHighlighter:206:

fun caretPositionChanged(e: CaretEvent) {
   ReadAction.nonBlocking(() -> {
       //.... calc some result in BGT...
   }
      .expireWhen(() -> !BackgroundHighlightingUtil.isValidEditor(hostEditor) ||
                        hostEditor.getCaretModel().getOffset() != offsetBefore)
      .coalesceBy(AbstractScopeHighlightingAction.class, hostEditor)
      .finishOnUiThread(ModalityState.stateForComponent(hostEditor.getComponent()), result -> {
        //... apply the result to the editor in EDT ...
      })
      .submit(AppExecutorUtil.getAppExecutorService());
}

It is even simpler in Kotlin coroutines. But one has to think of scope and "coalesce" a bit differently.

fun caretPositionChanged(e: CaretEvent) {
  curUpdate?.cancel()
  curUpdate = scope.async {
     val highlights = readAction {
         //  ... calc highlights in BGT ...
     }
     withContext(Dispatchers.EDT) {
         if (editor is closed or caret position changed) return
         // .. apply highlights in ED...
     }
  }
}
izhangzhihao commented 7 months ago

Thanks for the tips and sample code, it works now.