From 13b2ac3ef8b9536b5b189a77003033e2f041ea0b Mon Sep 17 00:00:00 2001 From: Yuriy Artamonov Date: Wed, 17 Sep 2025 10:15:26 +0200 Subject: [PATCH] [daemon] IJPL-206895 Autoreparse delay is set to `0` without a user action (cherry picked from commit ee112910b742836ee4dba68b43b5b5b3ad6c1d14) IJ-CR-176136 GitOrigin-RevId: 11b7b4bfaeb7d95bd548ccbeaa25c12957e37e5d --- platform/analysis-impl/api-dump.txt | 2 + .../daemon/DaemonCodeAnalyzerSettings.java | 21 ++++++- platform/ide-core/api-dump.txt | 1 + .../resources/messages/LangBundle.properties | 3 + .../daemon/impl/DaemonCodeAnalyzerImpl.java | 2 +- .../daemon/impl/MainPassesRunner.java | 5 +- .../impl/ResetAutoReparseSettingsActivity.kt | 58 +++++++++++++++++++ .../src/META-INF/PlatformExtensions.xml | 2 +- .../src/META-INF/PlatformLangComponents.xml | 1 + .../impl/CodeInsightTestFixtureImpl.java | 5 +- 10 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ResetAutoReparseSettingsActivity.kt diff --git a/platform/analysis-impl/api-dump.txt b/platform/analysis-impl/api-dump.txt index 26b4325c8bcc..d64609fc20d3 100644 --- a/platform/analysis-impl/api-dump.txt +++ b/platform/analysis-impl/api-dump.txt @@ -19,6 +19,8 @@ com.intellij.codeInsight.completion.CompletionLookupArranger - a:addElement(com.intellij.codeInsight.lookup.LookupElement,com.intellij.codeInsight.completion.CompletionSorter,com.intellij.codeInsight.completion.PrefixMatcher,com.intellij.codeInsight.lookup.LookupElementPresentation):V - a:arrangeItems():com.intellij.openapi.util.Pair - a:itemMatcher(com.intellij.codeInsight.lookup.LookupElement):com.intellij.codeInsight.completion.PrefixMatcher +c:com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings +- sf:AUTOREPARSE_DELAY_DEFAULT:I com.intellij.codeInsight.daemon.ReferenceImporter - sf:EP_NAME:com.intellij.openapi.extensions.ExtensionPointName - autoImportReferenceAtCursor(com.intellij.openapi.editor.Editor,com.intellij.psi.PsiFile):Z diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/DaemonCodeAnalyzerSettings.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/DaemonCodeAnalyzerSettings.java index dedec7aac383..2684c3fee4e6 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/DaemonCodeAnalyzerSettings.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/DaemonCodeAnalyzerSettings.java @@ -4,15 +4,21 @@ package com.intellij.codeInsight.daemon; import com.intellij.openapi.application.ApplicationManager; import com.intellij.util.xmlb.annotations.OptionTag; import com.intellij.util.xmlb.annotations.Transient; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NonNls; public class DaemonCodeAnalyzerSettings { + public static final int AUTOREPARSE_DELAY_DEFAULT = 300; + private boolean myNextErrorActionGoesToErrorsFirst = true; - private int myAutoReparseDelay = 300; + private int myAutoReparseDelay = AUTOREPARSE_DELAY_DEFAULT; private int myErrorStripeMarkMinHeight = 2; private boolean mySuppressWarnings = true; + @Transient + private volatile boolean myForceZeroAutoReparseDelay = false; + public static DaemonCodeAnalyzerSettings getInstance() { return ApplicationManager.getApplication().getService(DaemonCodeAnalyzerSettings.class); } @@ -36,6 +42,19 @@ public class DaemonCodeAnalyzerSettings { myAutoReparseDelay = millis; } + @ApiStatus.Internal + public void forceUseZeroAutoReparseDelay(boolean useZeroAutoReparseDelay) { + myForceZeroAutoReparseDelay = useZeroAutoReparseDelay; + } + + @Transient + @ApiStatus.Internal + public int getEffectiveAutoReparseDelay() { + if (myForceZeroAutoReparseDelay) return 0; + + return myAutoReparseDelay; + } + @OptionTag("ERROR_STRIPE_MARK_MIN_HEIGHT") public int getErrorStripeMarkMinHeight() { return myErrorStripeMarkMinHeight; diff --git a/platform/ide-core/api-dump.txt b/platform/ide-core/api-dump.txt index 62760c3495f7..0fc1829c7aa7 100644 --- a/platform/ide-core/api-dump.txt +++ b/platform/ide-core/api-dump.txt @@ -105,6 +105,7 @@ com.intellij.ide.wizard.Step com.intellij.ide.wizard.StepListener - java.util.EventListener - a:stateChanged():V +c:com.intellij.notification.Notification com.intellij.notification.NotificationGroupManager - s:getInstance():com.intellij.notification.NotificationGroupManager - a:getNotificationGroup(java.lang.String):com.intellij.notification.NotificationGroup diff --git a/platform/lang-api/resources/messages/LangBundle.properties b/platform/lang-api/resources/messages/LangBundle.properties index 8d5da8cd8f6e..111b27e64973 100644 --- a/platform/lang-api/resources/messages/LangBundle.properties +++ b/platform/lang-api/resources/messages/LangBundle.properties @@ -622,3 +622,6 @@ language.services.service.stopped.notification.content=The service will restart unscramble.progress.title.analyzing.stacktrace=Analyzing stacktrace\u2026 tooltip.unable.to.proceed.document.was.changed=Unable to proceed: document was changed shared.target.presentation.label=[shared] + +notification.content.editor.autoreparse.delay.has.been.restored=Editor autoreparse delay has been restored to the default value {0}ms. 0 value is associated with potential UI freezes and not recommended. +action.open.settings.text=Open Settings diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java index 9fbee1497013..39bc6619ebac 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java @@ -982,7 +982,7 @@ public final class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzerEx * reset {@link #myScheduledUpdateTimestamp} always, but re-schedule {@link #myUpdateRunnable} only rarely because of thread scheduling overhead */ private synchronized void scheduleIfNotRunning() { - long autoReparseDelayNanos = TimeUnit.MILLISECONDS.toNanos(mySettings.getAutoReparseDelay()); + long autoReparseDelayNanos = TimeUnit.MILLISECONDS.toNanos(mySettings.getEffectiveAutoReparseDelay()); myScheduledUpdateTimestamp = System.nanoTime() + autoReparseDelayNanos; // optimisation: this check is to avoid too many re-schedules in case of thousands of event spikes boolean isDone = myUpdateRunnableFuture.isDone(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/MainPassesRunner.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/MainPassesRunner.java index d008b164f043..bace59257779 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/MainPassesRunner.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/MainPassesRunner.java @@ -206,10 +206,9 @@ public final class MainPassesRunner { // repeat several times when accidental background activity cancels highlighting int retries = 100; for (int i = 0; i < retries; i++) { - int oldDelay = settings.getAutoReparseDelay(); try { InspectionProfile currentProfile = myInspectionProfile; - settings.setAutoReparseDelay(0); + settings.forceUseZeroAutoReparseDelay(true); Function profileProvider = p -> currentProfile == null ? new InspectionProfileWrapper((InspectionProfileImpl)p) @@ -230,7 +229,7 @@ public final class MainPassesRunner { exception = e; } finally { - settings.setAutoReparseDelay(oldDelay); + settings.forceUseZeroAutoReparseDelay(false); } } if (exception != null) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ResetAutoReparseSettingsActivity.kt b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ResetAutoReparseSettingsActivity.kt new file mode 100644 index 000000000000..d5b6a2871ab4 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ResetAutoReparseSettingsActivity.kt @@ -0,0 +1,58 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.codeInsight.daemon.impl + +import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings +import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings.AUTOREPARSE_DELAY_DEFAULT +import com.intellij.ide.actions.ShowSettingsUtilImpl +import com.intellij.ide.util.runOnceForApp +import com.intellij.lang.LangBundle +import com.intellij.notification.NotificationAction +import com.intellij.notification.NotificationGroupManager +import com.intellij.notification.NotificationType +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.backgroundWriteAction +import com.intellij.openapi.diagnostic.thisLogger +import com.intellij.openapi.extensions.ExtensionNotApplicableException +import com.intellij.openapi.options.ShowSettingsUtil +import com.intellij.openapi.options.ex.ConfigurableVisitor +import com.intellij.openapi.project.Project +import com.intellij.openapi.startup.ProjectActivity + +internal class ResetAutoReparseSettingsActivity : ProjectActivity { + init { + val app = ApplicationManager.getApplication() + if (app.isUnitTestMode || app.isHeadlessEnvironment || app.isCommandLine) { + throw ExtensionNotApplicableException.create() + } + } + + override suspend fun execute(project: Project) { + runOnceForApp("reset.auto.reparse.settings.to.default") { + val didChange = backgroundWriteAction { + val settings = DaemonCodeAnalyzerSettings.getInstance() + if (settings.autoReparseDelay == 0) { + settings.autoReparseDelay = AUTOREPARSE_DELAY_DEFAULT + + thisLogger().info("Setting AUTOREPARSE_DELAY default value as suspicious value 0 was stored in settings") + return@backgroundWriteAction true + } + false + } + + if (didChange) { + val notification = NotificationGroupManager.getInstance().getNotificationGroup("System Messages") + .createNotification(LangBundle.message("notification.content.editor.autoreparse.delay.has.been.restored", AUTOREPARSE_DELAY_DEFAULT), + NotificationType.INFORMATION) + notification.setDisplayId("reset.auto.reparse.settings.to.default") + notification.setSuppressShowingPopup(true) + notification.addAction(NotificationAction.create(LangBundle.message("action.open.settings.text")) { + val groups = ShowSettingsUtilImpl.getConfigurableGroups(project, withIdeSettings = true) + val configurable = ConfigurableVisitor.findById("preferences.editor.code.editing", groups.toList()) + + ShowSettingsUtil.getInstance().showSettingsDialog(project, configurable) + }) + notification.notify(project) + } + } + } +} \ No newline at end of file diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index 2aba2e452c8d..a6f52ff26b6f 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -1537,7 +1537,7 @@ + notificationIds="cloud.config.alert;glibc.incompatible;reset.auto.reparse.settings.to.default"/> + infos = new ArrayList<>(); EdtTestUtil.runInEdtAndWait(() -> { PsiFile file = filePointer.getElement(); @@ -345,7 +344,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig exception = e; } finally { - settings.setAutoReparseDelay(oldDelay); + settings.forceUseZeroAutoReparseDelay(false); } } ExceptionUtil.rethrow(exception);