diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java index e452f20f1d13..c9805d59c7f1 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -528,27 +528,33 @@ public class BuildManager implements Disposable { if (project == null || !canStartAutoMake(project)) { return; } - // todo: check if the system is in the idle state. If yes, run the make, if not, postpone and re-schedule it - final List scopes = CmdlineProtoUtil.createAllModulesScopes(false); - final AutoMakeMessageHandler handler = new AutoMakeMessageHandler(project); - final TaskFuture future = scheduleBuild( - project, false, true, false, scopes, Collections.emptyList(), Collections.emptyMap(), - handler - ); - if (future != null) { - myAutomakeFutures.put(future, project); - try { - future.waitFor(); - } - finally { - myAutomakeFutures.remove(future); - if (handler.unprocessedFSChangesDetected()) { - scheduleAutoMake(); + if (shouldPostponeAutomake()) { + // the system cannot be considered idle. Re-schedule the automake in order not to interfere with the user's activity + scheduleAutoMake(); + } + else { + // run automake + final List scopes = CmdlineProtoUtil.createAllModulesScopes(false); + final AutoMakeMessageHandler handler = new AutoMakeMessageHandler(project); + final TaskFuture future = scheduleBuild( + project, false, true, false, scopes, Collections.emptyList(), Collections.emptyMap(), + handler + ); + if (future != null) { + myAutomakeFutures.put(future, project); + try { + future.waitFor(); + } + finally { + myAutomakeFutures.remove(future); + if (handler.unprocessedFSChangesDetected()) { + scheduleAutoMake(); + } } } } } - + private static boolean canStartAutoMake(@NotNull Project project) { if (project.isDisposed()) { return false; @@ -560,6 +566,18 @@ public class BuildManager implements Disposable { return config.allowAutoMakeWhileRunningApplication() || !hasRunningProcess(project); } + private static boolean shouldPostponeAutomake() { + // Heuristics for postpone-decision: + // 1. There are unsaved documents OR + // 2. The IDE is not idle: the last activity happened less than 3 seconds ago (registry-configurable) + if (FileDocumentManager.getInstance().getUnsavedDocuments().length > 0) { + return true; + } + final long threshold = (long)Registry.intValue("compiler.automake.postpone.when.idle.less.than", 3000); // todo: UI option instead of registry? + final long idleSinceLastActivity = ApplicationManager.getApplication().getIdleTime(); + return idleSinceLastActivity < threshold; + } + @Nullable private Project getCurrentContextProject() { return getContextProject(null); diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 3914d3e8bc5a..e90d27634550 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -441,6 +441,9 @@ compiler.process.debug.port.description=Specifies build port at which build proc compiler.automake.trigger.delay=300 compiler.automake.trigger.delay.description=Delay in milliseconds before triggering auto-make in response to file system events +compiler.automake.postpone.when.idle.less.than=3000 +compiler.automake.postpone.when.idle.less.than.description=If at the moment the autobuild is about to start the IDE is idle for less than specified milliseconds, the the automatic build will be postponed in order not to interfere with teh user's activity + compiler.automake.allow.when.app.running=false compiler.automake.allow.when.app.running.description=Allow auto-make to start even if developed application is currently running. Note that automatically started make may eventually delete some classes that are required by the application.