[auto-reload] smoothed auto-reload

long delay before refresh
show auto-reload notification only for disabled part
don't auto-reload changes during project reload

GitOrigin-RevId: 5b75b0ddc2f0086bba43c3663f03100d20516eb5
This commit is contained in:
Sergei Vorobyov
2020-05-01 19:08:11 +03:00
committed by intellij-monorepo-bot
parent 2604c5a552
commit 840b326d48
4 changed files with 22 additions and 27 deletions

View File

@@ -43,7 +43,8 @@ class AutoImportProjectTracker(private val project: Project) : ExternalSystemPro
private val debugThrowable = Throwable("Initialized with project=(${project.isDisposed}, ${Disposer.isDisposed(project)}, $project)") private val debugThrowable = Throwable("Initialized with project=(${project.isDisposed}, ${Disposer.isDisposed(project)}, $project)")
private val LOG = Logger.getInstance("#com.intellij.openapi.externalSystem.autoimport") private val LOG = Logger.getInstance("#com.intellij.openapi.externalSystem.autoimport")
private val AUTO_REPARSE_DELAY get() = DaemonCodeAnalyzerSettings.getInstance().autoReparseDelay private val AUTO_REPARSE_DELAY = DaemonCodeAnalyzerSettings.getInstance().autoReparseDelay
private val AUTO_RELOAD_DELAY = 2000
private val settings get() = ProjectTrackerSettings.getInstance(project) private val settings get() = ProjectTrackerSettings.getInstance(project)
private val projectStates = ConcurrentHashMap<State.Id, State.Project>() private val projectStates = ConcurrentHashMap<State.Id, State.Project>()
@@ -53,6 +54,7 @@ class AutoImportProjectTracker(private val project: Project) : ExternalSystemPro
private val projectChangeOperation = AnonymousParallelOperationTrace(debugName = "Project change operation") private val projectChangeOperation = AnonymousParallelOperationTrace(debugName = "Project change operation")
private val projectRefreshOperation = CompoundParallelOperationTrace<String>(debugName = "Project refresh operation") private val projectRefreshOperation = CompoundParallelOperationTrace<String>(debugName = "Project refresh operation")
private val dispatcher = MergingUpdateQueue("AutoImportProjectTracker.dispatcher", AUTO_REPARSE_DELAY, false, null, project) private val dispatcher = MergingUpdateQueue("AutoImportProjectTracker.dispatcher", AUTO_REPARSE_DELAY, false, null, project)
private val delayDispatcher = MergingUpdateQueue("AutoImportProjectTracker.delayDispatcher", AUTO_RELOAD_DELAY, false, null, project)
private val backgroundExecutor = AppExecutorUtil.createBoundedApplicationPoolExecutor("AutoImportProjectTracker.backgroundExecutor", 1) private val backgroundExecutor = AppExecutorUtil.createBoundedApplicationPoolExecutor("AutoImportProjectTracker.backgroundExecutor", 1)
override var isAutoReloadExternalChanges by PropertyView( override var isAutoReloadExternalChanges by PropertyView(
@@ -91,7 +93,7 @@ class AutoImportProjectTracker(private val project: Project) : ExternalSystemPro
override fun scheduleProjectRefresh() { override fun scheduleProjectRefresh() {
LOG.debug("Schedule project refresh") LOG.debug("Schedule project refresh")
dispatcher.queue(PriorityEatUpdate(0) { dispatcher.queue(PriorityEatUpdate(0) {
refreshProject(doImportDeactivatedProjects = true) refreshProject(smart = false)
}) })
} }
@@ -109,30 +111,35 @@ class AutoImportProjectTracker(private val project: Project) : ExternalSystemPro
}) })
} }
private fun delay(action: () -> Unit) {
delayDispatcher.queue(Update.create(this, action))
}
private fun processChanges() { private fun processChanges() {
when (settings.autoReloadType) { when (settings.autoReloadType) {
AutoReloadType.ALL -> when (getModificationType()) { AutoReloadType.ALL -> when (getModificationType()) {
INTERNAL -> refreshProject(doImportDeactivatedProjects = false) INTERNAL -> delay { refreshProject(smart = true) }
EXTERNAL -> refreshProject(doImportDeactivatedProjects = false) EXTERNAL -> delay { refreshProject(smart = true) }
null -> updateProjectNotification() null -> updateProjectNotification()
} }
AutoReloadType.SELECTIVE -> when (getModificationType()) { AutoReloadType.SELECTIVE -> when (getModificationType()) {
INTERNAL -> updateProjectNotification() INTERNAL -> updateProjectNotification()
EXTERNAL -> refreshProject(doImportDeactivatedProjects = false) EXTERNAL -> delay { refreshProject(smart = true) }
null -> updateProjectNotification() null -> updateProjectNotification()
} }
AutoReloadType.NONE -> updateProjectNotification() AutoReloadType.NONE -> updateProjectNotification()
} }
} }
private fun refreshProject(doImportDeactivatedProjects: Boolean) { private fun refreshProject(smart: Boolean) {
LOG.debug("Incremental project refresh") LOG.debug("Incremental project refresh")
if (isDisabled.get() || Registry.`is`("external.system.auto.import.disabled")) return if (isDisabled.get() || Registry.`is`("external.system.auto.import.disabled")) return
if (!projectChangeOperation.isOperationCompleted()) return if (!projectChangeOperation.isOperationCompleted()) return
if (smart && !projectRefreshOperation.isOperationCompleted()) return
var isSkippedProjectRefresh = true var isSkippedProjectRefresh = true
for (projectData in projectDataMap.values) { for (projectData in projectDataMap.values) {
val projectId = projectData.projectAware.projectId.readableName val projectId = projectData.projectAware.projectId.readableName
val isAllowAutoReload = doImportDeactivatedProjects || projectData.isActivated val isAllowAutoReload = !smart || projectData.isActivated
if (isAllowAutoReload && !projectData.isUpToDate()) { if (isAllowAutoReload && !projectData.isUpToDate()) {
isSkippedProjectRefresh = false isSkippedProjectRefresh = false
LOG.debug("$projectId: Project refresh") LOG.debug("$projectId: Project refresh")
@@ -264,8 +271,12 @@ class AutoImportProjectTracker(private val project: Project) : ExternalSystemPro
LOG.debug("Project tracker initialization") LOG.debug("Project tracker initialization")
val connections = ApplicationManager.getApplication().messageBus.connect(project) val connections = ApplicationManager.getApplication().messageBus.connect(project)
connections.subscribe(BatchFileChangeListener.TOPIC, createProjectChangesListener()) connections.subscribe(BatchFileChangeListener.TOPIC, createProjectChangesListener())
dispatcher.setRestartTimerOnAdd(true)
dispatcher.isPassThrough = !isAsyncChangesProcessing dispatcher.isPassThrough = !isAsyncChangesProcessing
dispatcher.activate() dispatcher.activate()
delayDispatcher.setRestartTimerOnAdd(true)
delayDispatcher.isPassThrough = !isAsyncChangesProcessing
delayDispatcher.activate()
} }
@TestOnly @TestOnly
@@ -296,6 +307,7 @@ class AutoImportProjectTracker(private val project: Project) : ExternalSystemPro
projectChangeOperation.afterOperation { LOG.debug("Project change finished") } projectChangeOperation.afterOperation { LOG.debug("Project change finished") }
settings.autoReloadTypeProperty.afterChange { scheduleChangeProcessing() } settings.autoReloadTypeProperty.afterChange { scheduleChangeProcessing() }
asyncChangesProcessingProperty.afterChange { dispatcher.isPassThrough = !it } asyncChangesProcessingProperty.afterChange { dispatcher.isPassThrough = !it }
asyncChangesProcessingProperty.afterChange { delayDispatcher.isPassThrough = !it }
} }
private fun ProjectData.getState() = State.Project(status.isDirty(), settingsTracker.getState()) private fun ProjectData.getState() = State.Project(status.isDirty(), settingsTracker.getState())

View File

@@ -215,13 +215,8 @@ class ProjectSettingsTracker(
if (!hasChanges(newSettingsFilesCRC)) { if (!hasChanges(newSettingsFilesCRC)) {
status.markReverted(currentTime()) status.markReverted(currentTime())
} }
if (applyChangesOperation.isOperationCompleted()) {
projectTracker.scheduleChangeProcessing() projectTracker.scheduleChangeProcessing()
} }
else {
projectTracker.scheduleProjectNotificationUpdate()
}
}
} }
} }

View File

@@ -44,7 +44,8 @@ class ProjectAware(
} }
override fun refreshProject() { override fun refreshProject() {
ExternalSystemUtil.refreshProject(projectPath, ImportSpecBuilder(project, systemId).build()) val importSpec = ImportSpecBuilder(project, systemId).dontReportRefreshErrors()
ExternalSystemUtil.refreshProject(projectPath, importSpec)
} }
private inner class TaskNotificationListener( private inner class TaskNotificationListener(

View File

@@ -63,7 +63,6 @@ public class MavenProjectsManagerWatcher {
MessageBusConnection busConnection = myProject.getMessageBus().connect(myDisposable); MessageBusConnection busConnection = myProject.getMessageBus().connect(myDisposable);
busConnection.subscribe(ProjectTopics.MODULES, new MavenIgnoredModulesWatcher()); busConnection.subscribe(ProjectTopics.MODULES, new MavenIgnoredModulesWatcher());
busConnection.subscribe(ProjectTopics.PROJECT_ROOTS, new MyRootChangesListener()); busConnection.subscribe(ProjectTopics.PROJECT_ROOTS, new MyRootChangesListener());
myManager.addManagerListener(new MavenProjectWatcher());
registerGeneralSettingsWatcher(myManager, this, myBackgroundExecutor, myDisposable); registerGeneralSettingsWatcher(myManager, this, myBackgroundExecutor, myDisposable);
myProjectTracker.register(myProjectsAware); myProjectTracker.register(myProjectsAware);
myProjectTracker.activate(myProjectsAware.getProjectId()); myProjectTracker.activate(myProjectsAware.getProjectId());
@@ -202,16 +201,4 @@ public class MavenProjectsManagerWatcher {
if (mavenProject != null) myManager.setIgnoredState(Collections.singletonList(mavenProject), false); if (mavenProject != null) myManager.setIgnoredState(Collections.singletonList(mavenProject), false);
} }
} }
private class MavenProjectWatcher implements MavenProjectsManager.Listener {
@Override
public void projectsScheduled() {
scheduleReloadNotificationUpdate();
}
@Override
public void importAndResolveScheduled() {
scheduleReloadNotificationUpdate();
}
}
} }