From ea6a22250d47bd1e184dea69696ecbc2a3a74eac Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 20 Jul 2022 13:03:53 +0200 Subject: [PATCH] ProblemsViewImpl - create UI only when needed, rename "Classes up-to-Date Check" to "Refresh Compiler Reference Index", don't use extra thread for this activity GitOrigin-RevId: 9c7e8083f1d13fe5c33b43efa6674d4d1e365c4e --- .../compiler/CompilerConfigurationImpl.java | 3 +- .../compiler/CompilerManagerImpl.java | 8 +- .../com/intellij/compiler/ProblemsView.java | 8 +- .../IsUpToDateCheckStartupActivity.kt | 12 +- .../compiler/impl/CompileContextImpl.java | 18 +- .../intellij/compiler/impl/CompileDriver.kt | 1420 ++++++++--------- .../compiler/impl/CompileScopeUtil.java | 21 +- .../compiler/impl/CompilerErrorTreeView.java | 29 +- .../intellij/compiler/impl/CompilerUtil.java | 26 +- .../compiler/impl/ProblemsViewImpl.kt | 353 ++-- .../compiler/impl/ProblemsViewPanel.java | 48 - .../compiler/progress/CompilerTask.java | 6 +- .../compiler/server/AutoMakeMessageHandler.kt | 318 ++-- .../PreloadedProcessMessageHandler.java | 18 +- .../messages/JavaCompilerBundle.properties | 1 + .../intellij/compiler/ModuleCompilerUtil.java | 84 +- .../compiler/CompileStatusNotification.kt | 30 +- .../openapi/compiler/CompilerManager.java | 8 - .../openapi/compiler/CompilerPaths.java | 14 +- .../openapi/application/coroutines.kt | 14 +- .../intellij/build/BuildTreeConsoleView.java | 35 +- .../src/com/intellij/build/BuildView.java | 32 +- .../build/BuildTreeConsoleViewTest.kt | 4 +- .../openapi/wm/ToolWindowFactory.java | 2 +- .../intellij/openapi/wm/ToolWindowManager.kt | 12 +- .../com/intellij/util/ui/tree/TreeUtil.java | 261 ++- .../ide/errorTreeView/ErrorViewStructure.java | 62 +- .../errorTreeView/NewErrorTreeViewPanel.kt | 1129 ++++++------- .../errorTreeView/SimpleMessageElement.java | 4 +- .../openapi/wm/impl/ToolWindowIcon.kt | 72 +- .../openapi/wm/impl/ToolWindowImpl.kt | 10 +- .../intellij/ui/tree/StructureTreeModel.java | 3 +- .../intellij/util/concurrency/Invoker.java | 72 +- .../serviceContainer/ComponentManagerImpl.kt | 10 +- 34 files changed, 1879 insertions(+), 2268 deletions(-) delete mode 100644 java/compiler/impl/src/com/intellij/compiler/impl/ProblemsViewPanel.java diff --git a/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java b/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java index 550699625292..6607a1198473 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java @@ -115,7 +115,8 @@ public final class CompilerConfigurationImpl extends CompilerConfiguration imple @Override public void modulesAdded(@NotNull Project project, @NotNull List modules) { - myProcessorsProfilesMap = null; // clear cache + // clear cache + myProcessorsProfilesMap = null; } @Override diff --git a/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java b/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java index 1ebd44093e94..b869f6b6febf 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java @@ -51,7 +51,6 @@ import java.io.File; import java.io.IOException; import java.net.URI; import java.util.*; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -319,12 +318,7 @@ public class CompilerManagerImpl extends CompilerManager { @Override public boolean isUpToDate(@NotNull CompileScope scope) { - return new CompileDriver(myProject).isUpToDate(scope, true).join(); - } - - @Override - public CompletableFuture isUpToDateAsync(@NotNull CompileScope scope) { - return new CompileDriver(myProject).isUpToDate(scope, false); + return new CompileDriver(myProject).isUpToDate(scope); } @Override diff --git a/java/compiler/impl/src/com/intellij/compiler/ProblemsView.java b/java/compiler/impl/src/com/intellij/compiler/ProblemsView.java index 76cf52ffa57e..59677f6f8d71 100644 --- a/java/compiler/impl/src/com/intellij/compiler/ProblemsView.java +++ b/java/compiler/impl/src/com/intellij/compiler/ProblemsView.java @@ -52,7 +52,13 @@ public abstract class ProblemsView { public abstract void clearOldMessages(CompileScope scope, UUID currentSessionId); - public abstract void addMessage(int type, String @NotNull [] text, @Nullable String groupName, @Nullable Navigatable navigatable, @Nullable String exportTextPrefix, @Nullable String rendererTextPrefix, @NotNull UUID sessionId); + public abstract void addMessage(int type, + String @NotNull [] text, + @Nullable String groupName, + @Nullable Navigatable navigatable, + @Nullable String exportTextPrefix, + @Nullable String rendererTextPrefix, + @NotNull UUID sessionId); public final void addMessage(CompilerMessage message, @NotNull UUID sessionId) { final VirtualFile file = message.getVirtualFile(); diff --git a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/IsUpToDateCheckStartupActivity.kt b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/IsUpToDateCheckStartupActivity.kt index d5cf410d69f1..d0fcd51efb94 100644 --- a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/IsUpToDateCheckStartupActivity.kt +++ b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/IsUpToDateCheckStartupActivity.kt @@ -1,19 +1,19 @@ // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.compiler.backwardRefs +import com.intellij.compiler.impl.CompileDriver import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.compiler.CompilerManager +import com.intellij.openapi.compiler.JavaCompilerBundle import com.intellij.openapi.diagnostic.thisLogger import com.intellij.openapi.extensions.ExtensionNotApplicableException +import com.intellij.openapi.progress.withBackgroundProgressIndicator import com.intellij.openapi.project.Project import com.intellij.openapi.startup.ProjectPostStartupActivity import kotlinx.coroutines.ensureActive -import kotlinx.coroutines.future.asDeferred import kotlin.coroutines.coroutineContext /** - * Call [IsUpToDateCheckConsumer.isUpToDate] if [CompilerManager.isUpToDate] returns 'true'. - * * @see IsUpToDateCheckConsumer */ internal class IsUpToDateCheckStartupActivity : ProjectPostStartupActivity { @@ -37,8 +37,10 @@ internal class IsUpToDateCheckStartupActivity : ProjectPostStartupActivity { coroutineContext.ensureActive() - val compilerManager = CompilerManager.getInstance(project) - val isUpToDate = compilerManager.isUpToDateAsync(compilerManager.createProjectCompileScope(project)).asDeferred().await() + @Suppress("DialogTitleCapitalization") + val isUpToDate = withBackgroundProgressIndicator(project, JavaCompilerBundle.message("refresh.compiler.ref.index")) { + CompileDriver(project).nonBlockingIsUpToDate(CompilerManager.getInstance(project).createProjectCompileScope(project)) + } logger.info("isUpToDate = $isUpToDate") for (consumer in isUpToDateConsumers) { diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompileContextImpl.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompileContextImpl.java index bc6c6ec83701..d157cc2441c1 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileContextImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileContextImpl.java @@ -1,4 +1,4 @@ -// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. /* * @author Eugene Zhuravlev @@ -31,7 +31,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.UUID; -public class CompileContextImpl extends UserDataHolderBase implements CompileContextEx { +public final class CompileContextImpl extends UserDataHolderBase implements CompileContextEx { private static final Logger LOG = Logger.getInstance(CompileContextImpl.class); private final Project myProject; private final CompilerTask myBuildSession; @@ -74,8 +74,7 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon myShouldUpdateProblemsView = workspaceConfig.MAKE_PROJECT_ON_SAVE; } - @NotNull - public CompilerTask getBuildSession() { + public @NotNull CompilerTask getBuildSession() { return myBuildSession; } @@ -88,8 +87,7 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon } @Override - @NotNull - public Project getProject() { + public @NotNull Project getProject() { return myProject; } @@ -100,7 +98,7 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon @Override public void addMessage(@NotNull CompilerMessageCategory category, String message, String url, int lineNum, int columnNum, Navigatable navigatable, final Collection moduleNames) { - final CompilerMessage msg = myMessages.addMessage(category, message, url, lineNum, columnNum, navigatable, moduleNames); + CompilerMessage msg = myMessages.addMessage(category, message, url, lineNum, columnNum, navigatable, moduleNames); if (msg != null) { addToProblemsView(msg); } @@ -152,14 +150,12 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon } @Override - @Nullable - public String getRebuildReason() { + public @Nullable String getRebuildReason() { return myRebuildReason; } @Override - @NotNull - public ProgressIndicator getProgressIndicator() { + public @NotNull ProgressIndicator getProgressIndicator() { return myBuildSession.getIndicator(); } diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.kt b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.kt index 09a3ee5441f3..c351de365bd9 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.kt +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.kt @@ -1,950 +1,926 @@ // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.compiler.impl; +@file:Suppress("ReplacePutWithAssignment", "ReplaceGetOrSet") -import com.intellij.CommonBundle; -import com.intellij.build.BuildContentManager; -import com.intellij.compiler.*; -import com.intellij.compiler.progress.CompilerMessagesService; -import com.intellij.compiler.progress.CompilerTask; -import com.intellij.compiler.server.BuildManager; -import com.intellij.compiler.server.DefaultMessageHandler; -import com.intellij.configurationStore.StoreUtil; -import com.intellij.ide.nls.NlsMessages; -import com.intellij.notification.Notification; -import com.intellij.notification.NotificationListener; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.PathManager; -import com.intellij.openapi.application.ReadAction; -import com.intellij.openapi.application.ex.ApplicationManagerEx; -import com.intellij.openapi.compiler.*; -import com.intellij.openapi.deployment.DeploymentUtil; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.module.LanguageLevelUtil; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressIndicatorProvider; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.roots.CompilerModuleExtension; -import com.intellij.openapi.roots.ModuleRootManager; -import com.intellij.openapi.roots.ui.configuration.DefaultModuleConfigurationEditorFactory; -import com.intellij.openapi.ui.MessageType; -import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.NlsContexts; -import com.intellij.openapi.util.Ref; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.text.HtmlChunk; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VirtualFileManager; -import com.intellij.openapi.wm.*; -import com.intellij.packaging.artifacts.Artifact; -import com.intellij.packaging.impl.compiler.ArtifactCompilerUtil; -import com.intellij.packaging.impl.compiler.ArtifactsCompiler; -import com.intellij.pom.java.LanguageLevel; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.tracing.Tracer; -import com.intellij.util.Chunk; -import com.intellij.util.SystemProperties; -import com.intellij.util.ThrowableRunnable; -import com.intellij.util.containers.CollectionFactory; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.text.DateFormatUtil; -import org.jetbrains.annotations.*; -import org.jetbrains.jps.api.*; -import org.jetbrains.jps.model.java.JavaSourceRootType; +package com.intellij.compiler.impl -import javax.swing.*; -import javax.swing.event.HyperlinkEvent; -import java.awt.*; -import java.io.IOException; -import java.lang.ref.WeakReference; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; +import com.intellij.CommonBundle +import com.intellij.build.BuildContentManager +import com.intellij.compiler.* +import com.intellij.compiler.progress.CompilerMessagesService +import com.intellij.compiler.progress.CompilerTask +import com.intellij.compiler.server.BuildManager +import com.intellij.compiler.server.DefaultMessageHandler +import com.intellij.configurationStore.runInAutoSaveDisabledMode +import com.intellij.configurationStore.saveSettings +import com.intellij.ide.impl.runBlockingUnderModalProgress +import com.intellij.ide.nls.NlsMessages +import com.intellij.notification.Notification +import com.intellij.notification.NotificationListener +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.PathManager +import com.intellij.openapi.application.ReadAction +import com.intellij.openapi.application.ex.ApplicationManagerEx +import com.intellij.openapi.compiler.* +import com.intellij.openapi.deployment.DeploymentUtil +import com.intellij.openapi.diagnostic.debug +import com.intellij.openapi.diagnostic.logger +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.module.LanguageLevelUtil +import com.intellij.openapi.module.Module +import com.intellij.openapi.progress.* +import com.intellij.openapi.project.Project +import com.intellij.openapi.projectRoots.Sdk +import com.intellij.openapi.roots.CompilerModuleExtension +import com.intellij.openapi.roots.ModuleRootManager +import com.intellij.openapi.roots.ui.configuration.DefaultModuleConfigurationEditorFactory +import com.intellij.openapi.ui.MessageType +import com.intellij.openapi.ui.Messages +import com.intellij.openapi.util.Key +import com.intellij.openapi.util.NlsContexts +import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.util.text.HtmlChunk +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.openapi.vfs.VirtualFileManager +import com.intellij.openapi.wm.StatusBar +import com.intellij.openapi.wm.ToolWindowId +import com.intellij.openapi.wm.ToolWindowManager +import com.intellij.openapi.wm.WindowManager +import com.intellij.packaging.impl.compiler.ArtifactCompilerUtil +import com.intellij.packaging.impl.compiler.ArtifactsCompiler +import com.intellij.pom.java.LanguageLevel +import com.intellij.psi.PsiDocumentManager +import com.intellij.tracing.Tracer +import com.intellij.util.SystemProperties +import com.intellij.util.ThrowableRunnable +import com.intellij.util.containers.CollectionFactory +import com.intellij.util.containers.ContainerUtil +import com.intellij.util.io.write +import com.intellij.util.text.DateFormatUtil +import org.jetbrains.annotations.Nls +import org.jetbrains.annotations.NonNls +import org.jetbrains.annotations.PropertyKey +import org.jetbrains.annotations.TestOnly +import org.jetbrains.jps.api.* +import org.jetbrains.jps.api.CmdlineRemoteProto.Message.BuilderMessage +import org.jetbrains.jps.api.CmdlineRemoteProto.Message.BuilderMessage.CompileMessage +import org.jetbrains.jps.api.CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.TargetTypeBuildScope +import org.jetbrains.jps.model.java.JavaSourceRootType +import java.awt.EventQueue +import java.io.IOException +import java.lang.ref.WeakReference +import java.nio.file.Paths +import java.util.* +import java.util.concurrent.CancellationException +import java.util.concurrent.TimeUnit +import javax.swing.SwingUtilities +import javax.swing.event.HyperlinkEvent -import static org.jetbrains.jps.api.CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.TargetTypeBuildScope; +private val LOG = logger() +private val COMPILATION_STARTED_AUTOMATICALLY = Key.create("compilation_started_automatically") +private val COMPILE_SERVER_BUILD_STATUS = Key.create("COMPILE_SERVER_BUILD_STATUS") +private const val ONE_MINUTE_MS = 60L * 1000L -public final class CompileDriver { - private static final Logger LOG = Logger.getInstance(CompileDriver.class); +class CompileDriver(private val project: Project) { + private val moduleOutputPaths = HashMap() + private val moduleTestOutputPaths = HashMap() - private static final Key COMPILATION_STARTED_AUTOMATICALLY = Key.create("compilation_started_automatically"); - private static final Key COMPILE_SERVER_BUILD_STATUS = Key.create("COMPILE_SERVER_BUILD_STATUS"); - private static final long ONE_MINUTE_MS = 60L * 1000L; + companion object { + @JvmStatic + fun setCompilationStartedAutomatically(scope: CompileScope) { + //todo[nik] pass this option as a parameter to compile/make methods instead + scope.putUserData(COMPILATION_STARTED_AUTOMATICALLY, true) + } - private final Project myProject; - private final Map myModuleOutputPaths = new HashMap<>(); - private final Map myModuleTestOutputPaths = new HashMap<>(); + @TestOnly + @JvmStatic + fun getExternalBuildExitStatus(context: CompileContext): ExitStatus? { + return context.getUserData(COMPILE_SERVER_BUILD_STATUS) + } - public CompileDriver(Project project) { - myProject = project; + fun convertToCategory(kind: CompileMessage.Kind?): CompilerMessageCategory? { + return when (kind) { + CompileMessage.Kind.ERROR, CompileMessage.Kind.INTERNAL_BUILDER_ERROR -> CompilerMessageCategory.ERROR + CompileMessage.Kind.WARNING -> CompilerMessageCategory.WARNING + CompileMessage.Kind.INFO, CompileMessage.Kind.JPS_INFO, CompileMessage.Kind.OTHER -> CompilerMessageCategory.INFORMATION + else -> null + } + } } - @SuppressWarnings({"deprecation", "unused"}) - public void setCompilerFilter(@SuppressWarnings("unused") CompilerFilter compilerFilter) { + fun rebuild(callback: CompileStatusNotification) { + doRebuild(callback = callback, compileScope = ProjectCompileScope(project)) } - public void rebuild(CompileStatusNotification callback) { - doRebuild(callback, new ProjectCompileScope(myProject)); + fun make(scope: CompileScope, callback: CompileStatusNotification) { + make(scope = scope, withModalProgress = false, callback = callback) } - public void make(CompileScope scope, CompileStatusNotification callback) { - make(scope, false, callback); - } - - public void make(CompileScope scope, boolean withModalProgress, CompileStatusNotification callback) { + fun make(scope: CompileScope, withModalProgress: Boolean, callback: CompileStatusNotification) { if (validateCompilerConfiguration(scope)) { - startup(scope, false, false, withModalProgress, callback, null); + startup(scope = scope, forceCompile = false, withModalProgress = withModalProgress, callback = callback) } else { - callback.finished(true, 0, 0, DummyCompileContext.create(myProject)); + callback.finished(aborted = true, errors = 0, warnings = 0, compileContext = DummyCompileContext.create(project)) } } - public @NotNull CompletableFuture isUpToDate(@NotNull CompileScope scope, boolean oldBehaviour) { - if (LOG.isDebugEnabled()) { - LOG.debug("isUpToDate operation started"); + @Suppress("DuplicatedCode") + fun isUpToDate(scope: CompileScope): Boolean { + LOG.debug { "isUpToDate operation started" } + val task = CompilerTask( + project, + JavaCompilerBundle.message("classes.up.to.date.check"), /* headlessMode = */ + true, /* forceAsync = */ + false, /* waitForPreviousSession */ + false, + isCompilationStartedAutomatically(scope) + ) + val compileContext = CompileContextImpl(project, task, scope, true, false) + var result: ExitStatus? = null + val compileWork = Runnable { + val indicator = compileContext.progressIndicator + if (indicator.isCanceled || project.isDisposed) { + return@Runnable + } + val buildManager = BuildManager.getInstance() + try { + buildManager.postponeBackgroundTasks() + buildManager.cancelAutoMakeTasks(project) + val future = compileInExternalProcess(compileContext = compileContext, onlyCheckUpToDate = true) + if (future != null) { + while (!future.waitFor(200L, TimeUnit.MILLISECONDS)) { + if (indicator.isCanceled) { + future.cancel(false) + } + } + } + } + catch (e: Throwable) { + LOG.error(e) + } + finally { + val exitStatus = COMPILE_SERVER_BUILD_STATUS.get(compileContext) + task.setEndCompilationStamp(exitStatus, System.currentTimeMillis()) + result = exitStatus + buildManager.allowBackgroundTasks(false) + if (!project.isDisposed) { + CompilerCacheManager.getInstance(project).flushCaches() + } + } } - CompilerTask task = new CompilerTask( - myProject, + val indicatorProvider = ProgressIndicatorProvider.getInstance() + if (!EventQueue.isDispatchThread() && indicatorProvider.progressIndicator != null) { + // if called from background process on pooled thread, run synchronously + task.run(compileWork, null, indicatorProvider.progressIndicator) + } + else { + task.start(compileWork, null) + } + if (LOG.isDebugEnabled) { + LOG.debug("isUpToDate operation finished") + } + return result == ExitStatus.UP_TO_DATE + } + + @Suppress("DuplicatedCode") + suspend fun nonBlockingIsUpToDate(scope: CompileScope): Boolean { + val task = CompilerTask( + project, JavaCompilerBundle.message("classes.up.to.date.check"), /* headlessMode = */ true, /* forceAsync = */ false, /* waitForPreviousSession */ false, isCompilationStartedAutomatically(scope) - ); - CompileContextImpl compileContext = new CompileContextImpl(myProject, task, scope, true, false); + ) - Ref result = new Ref<>(); + val compileContext = CompileContextImpl(project, task, scope, true, false) + return runUnderIndicator { + var result: ExitStatus? = null + task.runUsingCurrentIndicator(Runnable { + val indicator = compileContext.progressIndicator + if (indicator.isCanceled || project.isDisposed) { + return@Runnable + } - Runnable compileWork = () -> { - ProgressIndicator indicator = compileContext.getProgressIndicator(); - if (indicator.isCanceled() || myProject.isDisposed()) { - return; - } - - final BuildManager buildManager = BuildManager.getInstance(); - try { - buildManager.postponeBackgroundTasks(); - buildManager.cancelAutoMakeTasks(myProject); - TaskFuture future = compileInExternalProcess(compileContext, true); - if (future != null) { - while (!future.waitFor(200L, TimeUnit.MILLISECONDS)) { - if (indicator.isCanceled()) { - future.cancel(false); + val buildManager = BuildManager.getInstance() + try { + buildManager.postponeBackgroundTasks() + buildManager.cancelAutoMakeTasks(project) + val future = compileInExternalProcess(compileContext = compileContext, onlyCheckUpToDate = true) + if (future != null) { + while (!future.waitFor(200L, TimeUnit.MILLISECONDS)) { + if (indicator.isCanceled) { + future.cancel(false) + } } } } - } - catch (Throwable e) { - LOG.error(e); - } - finally { - ExitStatus exitStatus = COMPILE_SERVER_BUILD_STATUS.get(compileContext); - task.setEndCompilationStamp(exitStatus, System.currentTimeMillis()); - result.set(exitStatus); - buildManager.allowBackgroundTasks(false); - if (!myProject.isDisposed()) { - CompilerCacheManager.getInstance(myProject).flushCaches(); + catch (e: CancellationException) { + throw e } - } - }; - - if (!oldBehaviour) { - return task.startAsync(compileWork, null).thenApply(__ -> ExitStatus.UP_TO_DATE.equals(result.get())); + catch (e: Throwable) { + LOG.error(e) + } + finally { + val exitStatus = COMPILE_SERVER_BUILD_STATUS.get(compileContext) + task.setEndCompilationStamp(exitStatus, System.currentTimeMillis()) + result = exitStatus + buildManager.allowBackgroundTasks(false) + if (!project.isDisposed) { + CompilerCacheManager.getInstance(project).flushCaches() + } + } + }, null) + result == ExitStatus.UP_TO_DATE } - - ProgressIndicatorProvider indicatorProvider = ProgressIndicatorProvider.getInstance(); - if (!EventQueue.isDispatchThread() && indicatorProvider.getProgressIndicator() != null) { - // if called from background process on pooled thread, run synchronously - task.run(compileWork, null, indicatorProvider.getProgressIndicator()); - } - else { - task.start(compileWork, null); - } - - if (LOG.isDebugEnabled()) { - LOG.debug("isUpToDate operation finished"); - } - - return CompletableFuture.completedFuture(ExitStatus.UP_TO_DATE.equals(result.get())); } - public void compile(CompileScope scope, CompileStatusNotification callback) { + fun compile(scope: CompileScope, callback: CompileStatusNotification) { if (validateCompilerConfiguration(scope)) { - startup(scope, false, true, callback, null); + startup(scope = scope, forceCompile = true, callback = callback) } else { - callback.finished(true, 0, 0, DummyCompileContext.create(myProject)); + callback.finished(aborted = true, errors = 0, warnings = 0, compileContext = DummyCompileContext.create(project)) } } - private void doRebuild(CompileStatusNotification callback, final CompileScope compileScope) { + private fun doRebuild(callback: CompileStatusNotification, compileScope: CompileScope) { if (validateCompilerConfiguration(compileScope)) { - startup(compileScope, true, false, callback, null); + startup(scope = compileScope, isRebuild = true, forceCompile = false, callback = callback) } else { - callback.finished(true, 0, 0, DummyCompileContext.create(myProject)); + callback.finished(aborted = true, errors = 0, warnings = 0, compileContext = DummyCompileContext.create(project)) } } - public static void setCompilationStartedAutomatically(CompileScope scope) { - //todo[nik] pass this option as a parameter to compile/make methods instead - scope.putUserData(COMPILATION_STARTED_AUTOMATICALLY, true); - } - - private static boolean isCompilationStartedAutomatically(CompileScope scope) { - return Boolean.TRUE.equals(scope.getUserData(COMPILATION_STARTED_AUTOMATICALLY)); - } - - private List getBuildScopes(@NotNull CompileContextImpl compileContext, CompileScope scope, Collection paths) { - List scopes = new ArrayList<>(); - final boolean forceBuild = !compileContext.isMake(); - List explicitScopes = CompileScopeUtil.getBaseScopeForExternalBuild(scope); + private fun getBuildScopes(compileContext: CompileContextImpl, + scope: CompileScope, + paths: Collection): List { + val scopes = ArrayList() + val forceBuild = !compileContext.isMake + val explicitScopes = CompileScopeUtil.getBaseScopeForExternalBuild(scope) if (explicitScopes != null) { - scopes.addAll(explicitScopes); + scopes.addAll(explicitScopes) } - else if (!compileContext.isRebuild() && (!paths.isEmpty() || !CompileScopeUtil.allProjectModulesAffected(compileContext))) { - CompileScopeUtil.addScopesForSourceSets(scope.getAffectedSourceSets(), scope.getAffectedUnloadedModules(), scopes, forceBuild); + else if (!compileContext.isRebuild && (!paths.isEmpty() || !CompileScopeUtil.allProjectModulesAffected(compileContext))) { + CompileScopeUtil.addScopesForSourceSets(scope.affectedSourceSets, scope.affectedUnloadedModules, scopes, forceBuild) } else { - final Collection sourceSets = scope.getAffectedSourceSets(); - boolean includeTests = sourceSets.isEmpty(); - for (ModuleSourceSet sourceSet : sourceSets) { - if (sourceSet.getType().isTest()) { - includeTests = true; - break; + val sourceSets = scope.affectedSourceSets + var includeTests = sourceSets.isEmpty() + for (sourceSet in sourceSets) { + if (sourceSet.type.isTest) { + includeTests = true + break } } if (includeTests) { - scopes.addAll(CmdlineProtoUtil.createAllModulesScopes(forceBuild)); + scopes.addAll(CmdlineProtoUtil.createAllModulesScopes(forceBuild)) } else { - scopes.add(CmdlineProtoUtil.createAllModulesProductionScope(forceBuild)); + scopes.add(CmdlineProtoUtil.createAllModulesProductionScope(forceBuild)) } } - if (paths.isEmpty()) { - scopes = mergeScopesFromProviders(scope, scopes, forceBuild); - } - return scopes; + return if (paths.isEmpty()) mergeScopesFromProviders(scope = scope, scopes = scopes, forceBuild = forceBuild) else scopes } - private List mergeScopesFromProviders(CompileScope scope, - List scopes, - boolean forceBuild) { - for (BuildTargetScopeProvider provider : BuildTargetScopeProvider.EP_NAME.getExtensions()) { - List providerScopes = ReadAction.compute( - () -> myProject.isDisposed() ? Collections.emptyList() - : provider.getBuildTargetScopes(scope, myProject, forceBuild)); - scopes = CompileScopeUtil.mergeScopes(scopes, providerScopes); + private fun mergeScopesFromProviders(scope: CompileScope, + scopes: List, + forceBuild: Boolean): List { + var result = scopes + for (provider in BuildTargetScopeProvider.EP_NAME.extensionList) { + val providerScopes = ReadAction.compute, RuntimeException> { + if (project.isDisposed) { + emptyList() + } + else { + provider.getBuildTargetScopes(scope, project, forceBuild) + } + } + result = CompileScopeUtil.mergeScopes(result, providerScopes) } - return scopes; + return result } - @Nullable - private TaskFuture compileInExternalProcess(@NotNull final CompileContextImpl compileContext, final boolean onlyCheckUpToDate) { - final CompileScope scope = compileContext.getCompileScope(); - final Collection paths = CompileScopeUtil.fetchFiles(compileContext); - List scopes = getBuildScopes(compileContext, scope, paths); + private fun compileInExternalProcess(compileContext: CompileContextImpl, onlyCheckUpToDate: Boolean): TaskFuture<*>? { + val scope = compileContext.compileScope + val paths = CompileScopeUtil.fetchFiles(compileContext) + val scopes = getBuildScopes(compileContext = compileContext, scope = scope, paths = paths) // need to pass scope's user data to server - final Map builderParams; - if (onlyCheckUpToDate) { - builderParams = new HashMap<>(); + val builderParams = HashMap() + if (!onlyCheckUpToDate) { + val exported = scope.exportUserData() + if (!exported.isEmpty()) { + for ((key, value) in exported) { + builderParams.put(key.toString(), value.toString()) + } + } + } + + if (!scope.affectedUnloadedModules.isEmpty()) { + builderParams.put(BuildParametersKeys.LOAD_UNLOADED_MODULES, true.toString()) + } + val outputToArtifact = if (ArtifactCompilerUtil.containsArtifacts(scopes)) { + ArtifactCompilerUtil.createOutputToArtifactMap(project) } else { - Map, Object> exported = scope.exportUserData(); - if (!exported.isEmpty()) { - builderParams = new HashMap<>(); - for (Map.Entry, Object> entry : exported.entrySet()) { - final String _key = entry.getKey().toString(); - final String _value = entry.getValue().toString(); - builderParams.put(_key, _value); + null + } + + return BuildManager.getInstance().scheduleBuild( + project, + compileContext.isRebuild, + compileContext.isMake, + onlyCheckUpToDate, + scopes, + paths, + builderParams, + object : DefaultMessageHandler(project) { + override fun sessionTerminated(sessionId: UUID) { + if (!onlyCheckUpToDate && compileContext.shouldUpdateProblemsView()) { + val view = ProblemsView.getInstanceIfCreated(project) ?: return + view.clearProgress() + view.clearOldMessages(compileContext.compileScope, compileContext.sessionId) + } } + + override fun handleFailure(sessionId: UUID, failure: CmdlineRemoteProto.Message.Failure) { + compileContext.addMessage(CompilerMessageCategory.ERROR, + if (failure.hasDescription()) failure.description else "", + null, + -1, + -1) + val trace = if (failure.hasStacktrace()) failure.stacktrace else null + if (trace != null) { + LOG.info(trace) + } + compileContext.putUserData(COMPILE_SERVER_BUILD_STATUS, ExitStatus.ERRORS) + } + + override fun handleCompileMessage(sessionId: UUID, message: CompileMessage) { + val kind = message.kind + val messageText = message.text + if (kind == CompileMessage.Kind.PROGRESS) { + val indicator = compileContext.progressIndicator + indicator.text = messageText + if (message.hasDone()) { + indicator.fraction = message.done.toDouble() + } + } + else { + val category = convertToCategory(kind = kind) ?: CompilerMessageCategory.INFORMATION + val sourceFilePath = if (message.hasSourceFilePath()) message.sourceFilePath?.let { FileUtil.toSystemIndependentName(it) } else null + val line = if (message.hasLine()) message.line else -1 + val column = if (message.hasColumn()) message.column else -1 + val srcUrl = if (sourceFilePath != null) VirtualFileManager.constructUrl(LocalFileSystem.PROTOCOL, sourceFilePath) else null + compileContext.addMessage(category, messageText, srcUrl, line.toInt(), column.toInt(), null, message.moduleNamesList) + if (compileContext.shouldUpdateProblemsView() && kind == CompileMessage.Kind.JPS_INFO) { + // treat JPS_INFO messages in a special way: add them as info messages to the problems view + val project = compileContext.project + ProblemsView.getInstance(project).addMessage(CompilerMessageImpl(project, category, messageText), compileContext.sessionId) + } + } + } + + override fun handleBuildEvent(sessionId: UUID, event: BuilderMessage.BuildEvent) { + when (event.eventType) { + BuilderMessage.BuildEvent.Type.FILES_GENERATED -> { + val generated = event.generatedFilesList + val publisher = if (project.isDisposed) null else project.messageBus.syncPublisher(CompilerTopics.COMPILATION_STATUS) + val writtenArtifactOutputPaths = if (outputToArtifact == null) null else CollectionFactory.createFilePathSet() + for (generatedFile in generated) { + val root = FileUtil.toSystemIndependentName(generatedFile.outputRoot) + val relativePath = FileUtil.toSystemIndependentName(generatedFile.relativePath) + publisher?.fileGenerated(root, relativePath) + if (outputToArtifact != null) { + val artifacts = outputToArtifact.get(root) + if (!artifacts.isNullOrEmpty()) { + writtenArtifactOutputPaths!!.add(FileUtil.toSystemDependentName(DeploymentUtil.appendToPath(root, relativePath))) + } + } + } + if (!writtenArtifactOutputPaths.isNullOrEmpty()) { + ArtifactsCompiler.addWrittenPaths(compileContext, writtenArtifactOutputPaths) + } + } + BuilderMessage.BuildEvent.Type.BUILD_COMPLETED -> { + var status = ExitStatus.SUCCESS + if (event.hasCompletionStatus()) { + when (event.completionStatus) { + BuilderMessage.BuildEvent.Status.CANCELED -> status = ExitStatus.CANCELLED + BuilderMessage.BuildEvent.Status.ERRORS -> status = ExitStatus.ERRORS + BuilderMessage.BuildEvent.Status.SUCCESS -> {} + BuilderMessage.BuildEvent.Status.UP_TO_DATE -> status = ExitStatus.UP_TO_DATE + null -> {} + } + } + compileContext.putUserDataIfAbsent(COMPILE_SERVER_BUILD_STATUS, status) + } + BuilderMessage.BuildEvent.Type.CUSTOM_BUILDER_MESSAGE -> { + if (event.hasCustomBuilderMessage()) { + val message = event.customBuilderMessage + if (GlobalOptions.JPS_SYSTEM_BUILDER_ID == message.builderId && + GlobalOptions.JPS_UNPROCESSED_FS_CHANGES_MESSAGE_ID == message.messageType) { + val text = message.messageText + if (!text.isNullOrEmpty()) { + compileContext.addMessage(CompilerMessageCategory.INFORMATION, text, null, -1, -1) + } + } + } + } + null -> { + } + } + } + + override fun getProgressIndicator(): ProgressIndicator = compileContext.progressIndicator } - else { - builderParams = new HashMap<>(); - } - } - if (!scope.getAffectedUnloadedModules().isEmpty()) { - builderParams.put(BuildParametersKeys.LOAD_UNLOADED_MODULES, Boolean.TRUE.toString()); - } - - Map> outputToArtifact = - ArtifactCompilerUtil.containsArtifacts(scopes) ? ArtifactCompilerUtil.createOutputToArtifactMap(myProject) : null; - return BuildManager.getInstance() - .scheduleBuild(myProject, compileContext.isRebuild(), compileContext.isMake(), onlyCheckUpToDate, scopes, paths, builderParams, - new DefaultMessageHandler(myProject) { - @Override - public void sessionTerminated(@NotNull UUID sessionId) { - if (!onlyCheckUpToDate && compileContext.shouldUpdateProblemsView()) { - ProblemsView view = myProject.getServiceIfCreated(ProblemsView.class); - if (view != null) { - view.clearProgress(); - view.clearOldMessages(compileContext.getCompileScope(), compileContext.getSessionId()); - } - } - } - - @Override - public void handleFailure(@NotNull UUID sessionId, CmdlineRemoteProto.Message.Failure failure) { - //noinspection HardCodedStringLiteral - compileContext - .addMessage(CompilerMessageCategory.ERROR, failure.hasDescription() ? failure.getDescription() : "", null, -1, - -1); - final String trace = failure.hasStacktrace() ? failure.getStacktrace() : null; - if (trace != null) { - LOG.info(trace); - } - compileContext.putUserData(COMPILE_SERVER_BUILD_STATUS, ExitStatus.ERRORS); - } - - @Override - protected void handleCompileMessage(UUID sessionId, - CmdlineRemoteProto.Message.BuilderMessage.CompileMessage message) { - final CmdlineRemoteProto.Message.BuilderMessage.CompileMessage.Kind kind = message.getKind(); - //System.out.println(compilerMessage.getText()); - //noinspection HardCodedStringLiteral - final String messageText = message.getText(); - if (kind == CmdlineRemoteProto.Message.BuilderMessage.CompileMessage.Kind.PROGRESS) { - final ProgressIndicator indicator = compileContext.getProgressIndicator(); - indicator.setText(messageText); - if (message.hasDone()) { - indicator.setFraction(message.getDone()); - } - } - else { - final CompilerMessageCategory category = convertToCategory(kind, CompilerMessageCategory.INFORMATION); - - String sourceFilePath = message.hasSourceFilePath() ? message.getSourceFilePath() : null; - if (sourceFilePath != null) { - sourceFilePath = FileUtil.toSystemIndependentName(sourceFilePath); - } - final long line = message.hasLine() ? message.getLine() : -1; - final long column = message.hasColumn() ? message.getColumn() : -1; - final String srcUrl = - sourceFilePath != null ? VirtualFileManager.constructUrl(LocalFileSystem.PROTOCOL, sourceFilePath) : null; - compileContext - .addMessage(category, messageText, srcUrl, (int)line, (int)column, null, message.getModuleNamesList()); - if (compileContext.shouldUpdateProblemsView() && - kind == CmdlineRemoteProto.Message.BuilderMessage.CompileMessage.Kind.JPS_INFO) { - // treat JPS_INFO messages in a special way: add them as info messages to the problems view - final Project project = compileContext.getProject(); - ProblemsView.getInstance(project).addMessage( - new CompilerMessageImpl(project, category, messageText), - compileContext.getSessionId() - ); - } - } - } - - @Override - protected void handleBuildEvent(UUID sessionId, CmdlineRemoteProto.Message.BuilderMessage.BuildEvent event) { - final CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Type eventType = event.getEventType(); - switch (eventType) { - case FILES_GENERATED: - final List generated = - event.getGeneratedFilesList(); - CompilationStatusListener publisher = - myProject.isDisposed() ? null : myProject.getMessageBus().syncPublisher(CompilerTopics.COMPILATION_STATUS); - Set writtenArtifactOutputPaths = - outputToArtifact != null ? CollectionFactory.createFilePathSet() : null; - for (CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.GeneratedFile generatedFile : generated) { - final String root = FileUtil.toSystemIndependentName(generatedFile.getOutputRoot()); - final String relativePath = FileUtil.toSystemIndependentName(generatedFile.getRelativePath()); - if (publisher != null) { - publisher.fileGenerated(root, relativePath); - } - if (outputToArtifact != null) { - Collection artifacts = outputToArtifact.get(root); - if (artifacts != null && !artifacts.isEmpty()) { - writtenArtifactOutputPaths - .add(FileUtil.toSystemDependentName(DeploymentUtil.appendToPath(root, relativePath))); - } - } - } - if (writtenArtifactOutputPaths != null && !writtenArtifactOutputPaths.isEmpty()) { - ArtifactsCompiler.addWrittenPaths(compileContext, writtenArtifactOutputPaths); - } - break; - - case BUILD_COMPLETED: - ExitStatus status = ExitStatus.SUCCESS; - if (event.hasCompletionStatus()) { - final CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status completionStatus = - event.getCompletionStatus(); - switch (completionStatus) { - case CANCELED: - status = ExitStatus.CANCELLED; - break; - case ERRORS: - status = ExitStatus.ERRORS; - break; - case SUCCESS: - break; - case UP_TO_DATE: - status = ExitStatus.UP_TO_DATE; - break; - } - } - compileContext.putUserDataIfAbsent(COMPILE_SERVER_BUILD_STATUS, status); - break; - - case CUSTOM_BUILDER_MESSAGE: - if (event.hasCustomBuilderMessage()) { - final CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.CustomBuilderMessage message = - event.getCustomBuilderMessage(); - if (GlobalOptions.JPS_SYSTEM_BUILDER_ID.equals(message.getBuilderId()) && - GlobalOptions.JPS_UNPROCESSED_FS_CHANGES_MESSAGE_ID.equals(message.getMessageType())) { - //noinspection HardCodedStringLiteral - final String text = message.getMessageText(); - if (!StringUtil.isEmpty(text)) { - compileContext.addMessage(CompilerMessageCategory.INFORMATION, text, null, -1, -1); - } - } - } - break; - } - } - - @Override - public @NotNull ProgressIndicator getProgressIndicator() { - return compileContext.getProgressIndicator(); - } - }); + ) } - private void startup(final CompileScope scope, final boolean isRebuild, final boolean forceCompile, - final CompileStatusNotification callback, final CompilerMessage message) { - startup(scope, isRebuild, forceCompile, false, callback, message); - } - - private void startup(final CompileScope scope, - final boolean isRebuild, - final boolean forceCompile, - boolean withModalProgress, final CompileStatusNotification callback, - final CompilerMessage message) { - ApplicationManager.getApplication().assertIsDispatchThread(); - - final boolean isUnitTestMode = ApplicationManager.getApplication().isUnitTestMode(); - final String name = JavaCompilerBundle - .message( - isRebuild ? "compiler.content.name.rebuild" : forceCompile ? "compiler.content.name.recompile" : "compiler.content.name.make"); - Tracer.Span span = Tracer.start(name + " preparation"); - final CompilerTask compileTask = new CompilerTask( - myProject, name, isUnitTestMode, !withModalProgress, true, isCompilationStartedAutomatically(scope), withModalProgress - ); - - StatusBar.Info.set("", myProject, "Compiler"); - - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - FileDocumentManager.getInstance().saveAllDocuments(); + private fun startup(scope: CompileScope, + isRebuild: Boolean = false, + forceCompile: Boolean, + withModalProgress: Boolean = false, + callback: CompileStatusNotification?, + message: CompilerMessage? = null) { + ApplicationManager.getApplication().assertIsDispatchThread() + val isUnitTestMode = ApplicationManager.getApplication().isUnitTestMode + val name = JavaCompilerBundle.message(when { + isRebuild -> "compiler.content.name.rebuild" + forceCompile -> "compiler.content.name.recompile" + else -> "compiler.content.name.make" + }) + val span = Tracer.start("$name preparation") + val compileTask = CompilerTask( + project, name, isUnitTestMode, !withModalProgress, true, isCompilationStartedAutomatically(scope), withModalProgress + ) + StatusBar.Info.set("", project, "Compiler") + PsiDocumentManager.getInstance(project).commitAllDocuments() + FileDocumentManager.getInstance().saveAllDocuments() // ensure the project model seen by build process is up-to-date - StoreUtil.saveSettings(myProject); - if (!isUnitTestMode) { - StoreUtil.saveSettings(ApplicationManager.getApplication()); + runInAutoSaveDisabledMode { + runBlockingUnderModalProgress { + saveSettings(project) + if (!isUnitTestMode) { + saveSettings(ApplicationManager.getApplication()) + } + } } - final CompileContextImpl compileContext = new CompileContextImpl(myProject, compileTask, scope, !isRebuild && !forceCompile, isRebuild); - span.complete(); - final Runnable compileWork = () -> { - Tracer.Span compileWorkSpan = Tracer.start("compileWork"); - final ProgressIndicator indicator = compileContext.getProgressIndicator(); - if (indicator.isCanceled() || myProject.isDisposed()) { - if (callback != null) { - callback.finished(true, 0, 0, compileContext); - } - return; + val compileContext = CompileContextImpl(project, compileTask, scope, !isRebuild && !forceCompile, isRebuild) + span.complete() + val compileWork = Runnable { + val compileWorkSpan = Tracer.start("compileWork") + val indicator = compileContext.progressIndicator + if (indicator.isCanceled || project.isDisposed) { + callback?.finished(true, 0, 0, compileContext) + return@Runnable } - CompilerCacheManager compilerCacheManager = CompilerCacheManager.getInstance(myProject); - final BuildManager buildManager = BuildManager.getInstance(); + + val compilerCacheManager = CompilerCacheManager.getInstance(project) + val buildManager = BuildManager.getInstance() try { - buildManager.postponeBackgroundTasks(); - buildManager.cancelAutoMakeTasks(myProject); - LOG.info("COMPILATION STARTED (BUILD PROCESS)"); + buildManager.postponeBackgroundTasks() + buildManager.cancelAutoMakeTasks(project) + LOG.info("COMPILATION STARTED (BUILD PROCESS)") if (message != null) { - compileContext.addMessage(message); + compileContext.addMessage(message) } if (isRebuild) { CompilerUtil.runInContext(compileContext, JavaCompilerBundle.message("progress.text.clearing.build.system.data"), - (ThrowableRunnable)() -> compilerCacheManager - .clearCaches(compileContext)); + ThrowableRunnable { compilerCacheManager.clearCaches(compileContext) }) } - final boolean beforeTasksOk = executeCompileTasks(compileContext, true); - - final int errorCount = compileContext.getMessageCount(CompilerMessageCategory.ERROR); + val beforeTasksOk = executeCompileTasks(context = compileContext, beforeTasks = true) + val errorCount = compileContext.getMessageCount(CompilerMessageCategory.ERROR) if (!beforeTasksOk || errorCount > 0) { - COMPILE_SERVER_BUILD_STATUS.set(compileContext, errorCount > 0 ? ExitStatus.ERRORS : ExitStatus.CANCELLED); - return; + COMPILE_SERVER_BUILD_STATUS.set(compileContext, if (errorCount > 0) ExitStatus.ERRORS else ExitStatus.CANCELLED) + return@Runnable } - - TaskFuture future = compileInExternalProcess(compileContext, false); + val future = compileInExternalProcess(compileContext, false) if (future != null) { - Tracer.Span compileInExternalProcessSpan = Tracer.start("compile in external process"); + val compileInExternalProcessSpan = Tracer.start("compile in external process") while (!future.waitFor(200L, TimeUnit.MILLISECONDS)) { - if (indicator.isCanceled()) { - future.cancel(false); + if (indicator.isCanceled) { + future.cancel(false) } } - compileInExternalProcessSpan.complete(); - if (!executeCompileTasks(compileContext, false)) { - COMPILE_SERVER_BUILD_STATUS.set(compileContext, ExitStatus.CANCELLED); + compileInExternalProcessSpan.complete() + if (!executeCompileTasks(context = compileContext, beforeTasks = false)) { + COMPILE_SERVER_BUILD_STATUS.set(compileContext, ExitStatus.CANCELLED) } if (compileContext.getMessageCount(CompilerMessageCategory.ERROR) > 0) { - COMPILE_SERVER_BUILD_STATUS.set(compileContext, ExitStatus.ERRORS); + COMPILE_SERVER_BUILD_STATUS.set(compileContext, ExitStatus.ERRORS) } } } - catch (ProcessCanceledException ignored) { - compileContext.putUserDataIfAbsent(COMPILE_SERVER_BUILD_STATUS, ExitStatus.CANCELLED); + catch (ignored: ProcessCanceledException) { + compileContext.putUserDataIfAbsent(COMPILE_SERVER_BUILD_STATUS, ExitStatus.CANCELLED) } - catch (Throwable e) { - LOG.error(e); // todo + catch (e: Throwable) { + LOG.error(e) // todo } finally { - compileWorkSpan.complete(); - buildManager.allowBackgroundTasks( - true // reset state on explicit build to compensate possibly unbalanced postpone/allow calls (e.g. via BatchFileChangeListener.start/stop) - ); - Tracer.Span flushCompilerCaches = Tracer.start("flush compiler caches"); - compilerCacheManager.flushCaches(); - flushCompilerCaches.complete(); + compileWorkSpan.complete() + // reset state on explicit build to compensate possibly unbalanced postpone/allow calls + // (e.g. via BatchFileChangeListener.start/stop) + buildManager.allowBackgroundTasks(true) - final long duration = notifyCompilationCompleted(compileContext, callback, COMPILE_SERVER_BUILD_STATUS.get(compileContext)); + val flushCompilerCaches = Tracer.start("flush compiler caches") + compilerCacheManager.flushCaches() + flushCompilerCaches.complete() + val duration = notifyCompilationCompleted(compileContext, callback, COMPILE_SERVER_BUILD_STATUS[compileContext]) CompilerUtil.logDuration( "\tCOMPILATION FINISHED (BUILD PROCESS); Errors: " + compileContext.getMessageCount(CompilerMessageCategory.ERROR) + "; warnings: " + compileContext.getMessageCount(CompilerMessageCategory.WARNING), duration - ); - + ) if (ApplicationManagerEx.isInIntegrationTest()) { - String logPath = PathManager.getLogPath(); - Path perfMetrics = Paths.get(logPath).resolve("performance-metrics").resolve("buildMetrics.json"); + val logPath = PathManager.getLogPath() + val perfMetrics = Paths.get(logPath).resolve("performance-metrics").resolve("buildMetrics.json") try { - FileUtil.writeToFile(perfMetrics.toFile(), "{\n\t\"build_errors\" : " + - compileContext.getMessageCount(CompilerMessageCategory.ERROR) + "," + - "\n\t\"build_warnings\" : " + - compileContext.getMessageCount(CompilerMessageCategory.WARNING) + "," + - "\n\t\"build_compilation_duration\" : " + - duration + - "\n}"); + perfMetrics.write("""{ + "build_errors" : ${compileContext.getMessageCount(CompilerMessageCategory.ERROR)}, + "build_warnings" : ${compileContext.getMessageCount(CompilerMessageCategory.WARNING)}, + "build_compilation_duration" : $duration +}""") } - catch (IOException ex) { - LOG.info("Could not create json file with the build performance metrics."); + catch (ex: IOException) { + LOG.info("Could not create json file with the build performance metrics.") } } } - }; - - compileTask.start(compileWork, () -> { + } + compileTask.start(compileWork) { if (isRebuild) { - final int rv = Messages.showOkCancelDialog( - myProject, JavaCompilerBundle.message("you.are.about.to.rebuild.the.whole.project"), + val rv = Messages.showOkCancelDialog( + project, JavaCompilerBundle.message("you.are.about.to.rebuild.the.whole.project"), JavaCompilerBundle.message("confirm.project.rebuild"), CommonBundle.message("button.build"), JavaCompilerBundle.message("button.rebuild"), Messages.getQuestionIcon() - ); + ) if (rv == Messages.OK /*yes, please, do run make*/) { - startup(scope, false, false, callback, null); - return; + startup(scope = scope, forceCompile = false, callback = callback) + return@start } } - startup(scope, isRebuild, forceCompile, callback, message); - }); - } - - @Nullable - @TestOnly - public static ExitStatus getExternalBuildExitStatus(CompileContext context) { - return context.getUserData(COMPILE_SERVER_BUILD_STATUS); + startup(scope = scope, isRebuild = isRebuild, forceCompile = forceCompile, callback = callback, message = message) + } } /** * @noinspection SSBasedInspection */ - private long notifyCompilationCompleted(final CompileContextImpl compileContext, - final CompileStatusNotification callback, - final ExitStatus _status) { - long endCompilationStamp = System.currentTimeMillis(); - compileContext.getBuildSession().setEndCompilationStamp(_status, endCompilationStamp); - final long duration = endCompilationStamp - compileContext.getStartCompilationStamp(); - if (!myProject.isDisposed()) { + private fun notifyCompilationCompleted(compileContext: CompileContextImpl, + callback: CompileStatusNotification?, + exitStatus: ExitStatus): Long { + val endCompilationStamp = System.currentTimeMillis() + compileContext.buildSession.setEndCompilationStamp(exitStatus, endCompilationStamp) + val duration = endCompilationStamp - compileContext.startCompilationStamp + if (!project.isDisposed) { // refresh on output roots is required in order for the order enumerator to see all roots via VFS - final Module[] affectedModules = compileContext.getCompileScope().getAffectedModules(); - - if (_status != ExitStatus.UP_TO_DATE && _status != ExitStatus.CANCELLED) { + val affectedModules = compileContext.compileScope.affectedModules + if (exitStatus !== ExitStatus.UP_TO_DATE && exitStatus !== ExitStatus.CANCELLED) { // have to refresh in case of errors too, because run configuration may be set to ignore errors - Collection affectedRoots = ContainerUtil.newHashSet(CompilerPaths.getOutputPaths(affectedModules)); + val affectedRoots = CompilerPaths.getOutputPaths(affectedModules).toHashSet() if (!affectedRoots.isEmpty()) { - ProgressIndicator indicator = compileContext.getProgressIndicator(); - indicator.setText(JavaCompilerBundle.message("synchronizing.output.directories")); - CompilerUtil.refreshOutputRoots(affectedRoots); - indicator.setText(""); + val indicator = compileContext.progressIndicator + indicator.text = JavaCompilerBundle.message("synchronizing.output.directories") + CompilerUtil.refreshOutputRoots(affectedRoots) + indicator.text = "" } } } - SwingUtilities.invokeLater(() -> { - int errorCount = 0; - int warningCount = 0; + SwingUtilities.invokeLater { + var errorCount = 0 + var warningCount = 0 try { - errorCount = compileContext.getMessageCount(CompilerMessageCategory.ERROR); - warningCount = compileContext.getMessageCount(CompilerMessageCategory.WARNING); + errorCount = compileContext.getMessageCount(CompilerMessageCategory.ERROR) + warningCount = compileContext.getMessageCount(CompilerMessageCategory.WARNING) } finally { - if (callback != null) { - callback.finished(_status == ExitStatus.CANCELLED, errorCount, warningCount, compileContext); - } + callback?.finished(exitStatus === ExitStatus.CANCELLED, errorCount, warningCount, compileContext) } - - if (!myProject.isDisposed()) { - final String statusMessage = createStatusMessage(_status, warningCount, errorCount, duration); - final MessageType messageType = errorCount > 0 ? MessageType.ERROR : warningCount > 0 ? MessageType.WARNING : MessageType.INFO; - if (duration > ONE_MINUTE_MS && CompilerWorkspaceConfiguration.getInstance(myProject).DISPLAY_NOTIFICATION_POPUP) { - String toolWindowId = useBuildToolWindow() ? BuildContentManager.TOOL_WINDOW_ID : ToolWindowId.MESSAGES_WINDOW; - ToolWindowManager.getInstance(myProject).notifyByBalloon(toolWindowId, messageType, statusMessage); + if (!project.isDisposed) { + val statusMessage = createStatusMessage(status = exitStatus, warningCount = warningCount, errorCount = errorCount, duration = duration) + val messageType = if (errorCount > 0) MessageType.ERROR else if (warningCount > 0) MessageType.WARNING else MessageType.INFO + if (duration > ONE_MINUTE_MS && CompilerWorkspaceConfiguration.getInstance(project).DISPLAY_NOTIFICATION_POPUP) { + val toolWindowId = if (useBuildToolWindow()) BuildContentManager.TOOL_WINDOW_ID else ToolWindowId.MESSAGES_WINDOW + ToolWindowManager.getInstance(project).notifyByBalloon(toolWindowId, messageType, statusMessage) } - String wrappedMessage = _status == ExitStatus.UP_TO_DATE ? statusMessage : HtmlChunk.link("#", statusMessage).toString(); - Notification notification = CompilerManager.NOTIFICATION_GROUP.createNotification(wrappedMessage, messageType.toNotificationType()) - .setListener(new BuildToolWindowActivationListener(compileContext)) - .setImportant(false); - compileContext.getBuildSession().registerCloseAction(notification::expire); - notification.notify(myProject); - - if (_status != ExitStatus.UP_TO_DATE && compileContext.getMessageCount(null) > 0) { - final String msg = DateFormatUtil.formatDateTime(new Date()) + " - " + statusMessage; - compileContext.addMessage(CompilerMessageCategory.INFORMATION, msg, null, -1, -1); + val wrappedMessage = if (exitStatus === ExitStatus.UP_TO_DATE) statusMessage else HtmlChunk.link("#", statusMessage).toString() + @Suppress("DEPRECATION") + val notification = CompilerManager.NOTIFICATION_GROUP.createNotification(wrappedMessage, messageType.toNotificationType()) + .setListener(BuildToolWindowActivationListener(compileContext)) + .setImportant(false) + compileContext.buildSession.registerCloseAction { notification.expire() } + notification.notify(project) + if (exitStatus !== ExitStatus.UP_TO_DATE && compileContext.getMessageCount(null) > 0) { + val msg = DateFormatUtil.formatDateTime(Date()) + " - " + statusMessage + compileContext.addMessage(CompilerMessageCategory.INFORMATION, msg, null, -1, -1) } } - }); - return duration; + } + return duration } - private static @Nls String createStatusMessage(final ExitStatus status, final int warningCount, final int errorCount, long duration) { - String message; - if (status == ExitStatus.CANCELLED) { - message = JavaCompilerBundle.message("status.compilation.aborted"); - } - else if (status == ExitStatus.UP_TO_DATE) { - message = JavaCompilerBundle.message("status.all.up.to.date"); - } - else { - String durationString = NlsMessages.formatDurationApproximate(duration); - if (status == ExitStatus.SUCCESS) { - message = warningCount > 0 - ? JavaCompilerBundle.message("status.compilation.completed.successfully.with.warnings", warningCount, durationString) - : JavaCompilerBundle.message("status.compilation.completed.successfully", durationString); - } - else { - message = JavaCompilerBundle.message("status.compilation.completed.successfully.with.warnings.and.errors", - errorCount, warningCount, durationString); - } - } - return message; + private fun getModuleOutputPath(module: Module, inTestSourceContent: Boolean): String? { + val map: MutableMap = if (inTestSourceContent) moduleTestOutputPaths else moduleOutputPaths + return map.computeIfAbsent(module) { CompilerPaths.getModuleOutputPath(module, inTestSourceContent) } } - // [mike] performance optimization - this method is accessed > 15,000 times in Aurora - private String getModuleOutputPath(Module module, boolean inTestSourceContent) { - Map map = inTestSourceContent ? myModuleTestOutputPaths : myModuleOutputPaths; - return map.computeIfAbsent(module, k -> CompilerPaths.getModuleOutputPath(module, inTestSourceContent)); + fun executeCompileTask(task: CompileTask, + scope: CompileScope, + contentName: @NlsContexts.TabTitle String?, + onTaskFinished: Runnable?) { + val progressManagerTask = CompilerTask(project, contentName, false, false, true, isCompilationStartedAutomatically(scope)) + val compileContext = CompileContextImpl(project, progressManagerTask, scope, false, false) + FileDocumentManager.getInstance().saveAllDocuments() + progressManagerTask.start({ + try { + task.execute(compileContext) + } + catch (ex: ProcessCanceledException) { + // suppressed + } + finally { + onTaskFinished?.run() + } + }, null) } - public void executeCompileTask(final CompileTask task, - final CompileScope scope, - final @NlsContexts.TabTitle String contentName, - final Runnable onTaskFinished) { - final CompilerTask progressManagerTask = - new CompilerTask(myProject, contentName, false, false, true, isCompilationStartedAutomatically(scope)); - final CompileContextImpl compileContext = new CompileContextImpl(myProject, progressManagerTask, scope, false, false); - - FileDocumentManager.getInstance().saveAllDocuments(); - - progressManagerTask.start(() -> { - try { - task.execute(compileContext); - } - catch (ProcessCanceledException ex) { - // suppressed - } - finally { - if (onTaskFinished != null) { - onTaskFinished.run(); - } - } - }, null); - } - - private boolean executeCompileTasks(@NotNull final CompileContext context, final boolean beforeTasks) { - if (myProject.isDisposed()) { - return false; + private fun executeCompileTasks(context: CompileContext, beforeTasks: Boolean): Boolean { + if (project.isDisposed) { + return false } - final CompilerManager manager = CompilerManager.getInstance(myProject); - final ProgressIndicator progressIndicator = context.getProgressIndicator(); - progressIndicator.pushState(); + + val manager = CompilerManager.getInstance(project) + val progressIndicator = context.progressIndicator + progressIndicator.pushState() try { - List tasks = beforeTasks ? manager.getBeforeTasks() : manager.getAfterTaskList(); - if (tasks.size() > 0) { - progressIndicator.setText( - JavaCompilerBundle.message(beforeTasks ? "progress.executing.precompile.tasks" : "progress.executing.postcompile.tasks")); - for (CompileTask task : tasks) { + val tasks = if (beforeTasks) manager.beforeTasks else manager.afterTaskList + if (tasks.size > 0) { + progressIndicator.text = JavaCompilerBundle.message( + if (beforeTasks) "progress.executing.precompile.tasks" else "progress.executing.postcompile.tasks" + ) + for (task in tasks) { try { if (!task.execute(context)) { - return false; + return false } } - catch (ProcessCanceledException e) { - throw e; + catch (e: ProcessCanceledException) { + throw e } - catch (Throwable t) { - LOG.error("Error executing task", t); - context - .addMessage(CompilerMessageCategory.INFORMATION, JavaCompilerBundle.message("error.task.0.execution.failed", task.toString()), - null, -1, -1); + catch (t: Throwable) { + LOG.error("Error executing task", t) + context.addMessage(CompilerMessageCategory.INFORMATION, + JavaCompilerBundle.message("error.task.0.execution.failed", task.toString()), + null, + -1, + -1) } } } } finally { - progressIndicator.popState(); - StatusBar statusBar = WindowManager.getInstance().getStatusBar(myProject); - if (statusBar != null) { - statusBar.setInfo(""); + progressIndicator.popState() + WindowManager.getInstance().getStatusBar(project)?.let { + it.info = "" } } - return true; + return true } - private boolean validateCompilerConfiguration(@NotNull final CompileScope scope) { + private fun validateCompilerConfiguration(scope: CompileScope): Boolean { try { - final Module[] scopeModules = scope.getAffectedModules(); - final CompilerManager compilerManager = CompilerManager.getInstance(myProject); - List modulesWithSources = ContainerUtil.filter(scopeModules, module -> { - if (!compilerManager.isValidationEnabled(module)) return false; - final boolean hasSources = hasSources(module, JavaSourceRootType.SOURCE); - final boolean hasTestSources = hasSources(module, JavaSourceRootType.TEST_SOURCE); - if (!hasSources && !hasTestSources) { - // If module contains no sources, shouldn't have to select JDK or output directory (SCR #19333) - // todo still there may be problems with this approach if some generated files are attributed by this module - return false; + val scopeModules = scope.affectedModules + val compilerManager = CompilerManager.getInstance(project) + val modulesWithSources = scopeModules.filter { module -> + if (!compilerManager.isValidationEnabled(module)) { + return@filter false } - return true; - }); - if (!validateJdks(modulesWithSources, true)) return false; - if (!validateOutputs(modulesWithSources)) return false; - if (!validateCyclicDependencies(scopeModules)) return false; - return true; + val hasSources = hasSources(module, JavaSourceRootType.SOURCE) + val hasTestSources = hasSources(module, JavaSourceRootType.TEST_SOURCE) + // If module contains no sources, shouldn't have to select JDK or output directory (SCR #19333) + // todo still there may be problems with this approach if some generated files are attributed by this module + hasSources || hasTestSources + } + if (!validateJdks(modulesWithSources, true)) { + return false + } + if (!validateOutputs(modulesWithSources)) { + return false + } + return validateCyclicDependencies(scopeModules) } - catch (ProcessCanceledException e) { - return false; + catch (ignore: ProcessCanceledException) { } - catch (Throwable e) { - LOG.error(e); - return false; + catch (e: Throwable) { + LOG.error(e) } + return false } - private boolean validateJdks(@NotNull List scopeModules, boolean runUnknownSdkCheck) { - final List modulesWithoutJdkAssigned = new ArrayList<>(); - boolean projectSdkNotSpecified = false; - for (final Module module : scopeModules) { - final Sdk jdk = ModuleRootManager.getInstance(module).getSdk(); - if (jdk != null) continue; - projectSdkNotSpecified |= ModuleRootManager.getInstance(module).isSdkInherited(); - modulesWithoutJdkAssigned.add(module.getName()); + private fun validateJdks(scopeModules: List, runUnknownSdkCheck: Boolean): Boolean { + val modulesWithoutJdkAssigned = ArrayList() + var projectSdkNotSpecified = false + for (module in scopeModules) { + val jdk = ModuleRootManager.getInstance(module).sdk + if (jdk != null) { + continue + } + + projectSdkNotSpecified = projectSdkNotSpecified or ModuleRootManager.getInstance(module).isSdkInherited + modulesWithoutJdkAssigned.add(module.name) } if (runUnknownSdkCheck) { - var result = CompilerDriverUnknownSdkTracker - .getInstance(myProject) - .fixSdkSettings(projectSdkNotSpecified, scopeModules, formatModulesList(modulesWithoutJdkAssigned)); - - if (result == CompilerDriverUnknownSdkTracker.Outcome.STOP_COMPILE) { - return false; - } - + val result = CompilerDriverUnknownSdkTracker + .getInstance(project) + .fixSdkSettings(projectSdkNotSpecified, scopeModules, formatModulesList(modulesWithoutJdkAssigned)) + return if (result === CompilerDriverUnknownSdkTracker.Outcome.STOP_COMPILE) false else validateJdks(scopeModules, false) //we do not trust the CompilerDriverUnknownSdkTracker, to extra check has to be done anyway - return validateJdks(scopeModules, false); } else { - if (modulesWithoutJdkAssigned.isEmpty()) return true; + if (modulesWithoutJdkAssigned.isEmpty()) { + return true + } showNotSpecifiedError("error.jdk.not.specified", projectSdkNotSpecified, modulesWithoutJdkAssigned, - JavaCompilerBundle.message("modules.classpath.title")); - return false; + JavaCompilerBundle.message("modules.classpath.title")) + return false } } - private boolean validateOutputs(@NotNull List scopeModules) { - final List modulesWithoutOutputPathSpecified = new ArrayList<>(); - boolean projectOutputNotSpecified = false; - for (final Module module : scopeModules) { - final String outputPath = getModuleOutputPath(module, false); - final String testsOutputPath = getModuleOutputPath(module, true); + private fun validateOutputs(scopeModules: List): Boolean { + val modulesWithoutOutputPathSpecified = ArrayList() + var projectOutputNotSpecified = false + for (module in scopeModules) { + val outputPath = getModuleOutputPath(module = module, inTestSourceContent = false) + val testsOutputPath = getModuleOutputPath(module = module, inTestSourceContent = true) if (outputPath == null && testsOutputPath == null) { - CompilerModuleExtension compilerExtension = CompilerModuleExtension.getInstance(module); - projectOutputNotSpecified |= compilerExtension != null && compilerExtension.isCompilerOutputPathInherited(); - modulesWithoutOutputPathSpecified.add(module.getName()); + val compilerExtension = CompilerModuleExtension.getInstance(module) + projectOutputNotSpecified = projectOutputNotSpecified or (compilerExtension != null && compilerExtension.isCompilerOutputPathInherited) + modulesWithoutOutputPathSpecified.add(module.name) } else { if (outputPath == null) { if (hasSources(module, JavaSourceRootType.SOURCE)) { - modulesWithoutOutputPathSpecified.add(module.getName()); + modulesWithoutOutputPathSpecified.add(module.name) } } if (testsOutputPath == null) { if (hasSources(module, JavaSourceRootType.TEST_SOURCE)) { - modulesWithoutOutputPathSpecified.add(module.getName()); + modulesWithoutOutputPathSpecified.add(module.name) } } } } - - if (modulesWithoutOutputPathSpecified.isEmpty()) return true; - + if (modulesWithoutOutputPathSpecified.isEmpty()) { + return true + } showNotSpecifiedError("error.output.not.specified", projectOutputNotSpecified, modulesWithoutOutputPathSpecified, - DefaultModuleConfigurationEditorFactory.getInstance().getOutputEditorDisplayName()); - return false; + DefaultModuleConfigurationEditorFactory.getInstance().outputEditorDisplayName) + return false } - private boolean validateCyclicDependencies(Module[] scopeModules) { - final List> chunks = ModuleCompilerUtil.getCyclicDependencies(myProject, Arrays.asList(scopeModules)); - for (final Chunk chunk : chunks) { - final Set sourceSets = chunk.getNodes(); - if (sourceSets.size() <= 1) { - continue; // no need to check one-module chunks + private fun validateCyclicDependencies(scopeModules: Array): Boolean { + val chunks = ModuleCompilerUtil.getCyclicDependencies(project, scopeModules.asList()) + for (chunk in chunks) { + val sourceSets = chunk.nodes + if (sourceSets.size <= 1) { + // no need to check one-module chunks + continue } - Sdk jdk = null; - LanguageLevel languageLevel = null; - for (final ModuleSourceSet sourceSet : sourceSets) { - Module module = sourceSet.getModule(); - final Sdk moduleJdk = ModuleRootManager.getInstance(module).getSdk(); + + var jdk: Sdk? = null + var languageLevel: LanguageLevel? = null + for (sourceSet in sourceSets) { + val module = sourceSet.module + val moduleJdk = ModuleRootManager.getInstance(module).sdk if (jdk == null) { - jdk = moduleJdk; + jdk = moduleJdk } else { - if (!jdk.equals(moduleJdk)) { - showCyclicModulesErrorNotification("error.chunk.modules.must.have.same.jdk", ModuleSourceSet.getModules(sourceSets)); - return false; + if (jdk != moduleJdk) { + showCyclicModulesErrorNotification("error.chunk.modules.must.have.same.jdk", ModuleSourceSet.getModules(sourceSets)) + return false } } - - LanguageLevel moduleLanguageLevel = LanguageLevelUtil.getEffectiveLanguageLevel(module); + val moduleLanguageLevel = LanguageLevelUtil.getEffectiveLanguageLevel(module) if (languageLevel == null) { - languageLevel = moduleLanguageLevel; + languageLevel = moduleLanguageLevel } else { - if (!languageLevel.equals(moduleLanguageLevel)) { - showCyclicModulesErrorNotification("error.chunk.modules.must.have.same.language.level", ModuleSourceSet.getModules(sourceSets)); - return false; + if (languageLevel != moduleLanguageLevel) { + showCyclicModulesErrorNotification("error.chunk.modules.must.have.same.language.level", ModuleSourceSet.getModules(sourceSets)) + return false } } } } - return true; + return true } - private void showCyclicModulesErrorNotification(@PropertyKey(resourceBundle = JavaCompilerBundle.BUNDLE) @NotNull String messageId, - @NotNull Set modulesInChunk) { - Module firstModule = ContainerUtil.getFirstItem(modulesInChunk); - LOG.assertTrue(firstModule != null); - CompileDriverNotifications.getInstance(myProject) + private fun showCyclicModulesErrorNotification(messageId: @PropertyKey(resourceBundle = JavaCompilerBundle.BUNDLE) String, + modulesInChunk: Set) { + val firstModule = modulesInChunk.first() + CompileDriverNotifications.getInstance(project) .createCannotStartNotification() .withContent(JavaCompilerBundle.message(messageId, getModulesString(modulesInChunk))) - .withOpenSettingsAction(firstModule.getName(), null) - .showNotification(); + .withOpenSettingsAction(firstModule.name, null) + .showNotification() } - private static String getModulesString(Collection modulesInChunk) { - return StringUtil.join(modulesInChunk, module -> "\"" + module.getName() + "\"", "\n"); - } - - private static boolean hasSources(Module module, final JavaSourceRootType rootType) { - return !ModuleRootManager.getInstance(module).getSourceRoots(rootType).isEmpty(); - } - - private void showNotSpecifiedError(@PropertyKey(resourceBundle = JavaCompilerBundle.BUNDLE) @NonNls String resourceId, - boolean notSpecifiedValueInheritedFromProject, - List modules, - String editorNameToSelect) { - String nameToSelect = notSpecifiedValueInheritedFromProject ? null : ContainerUtil.getFirstItem(modules); - final String message = JavaCompilerBundle.message(resourceId, modules.size(), formatModulesList(modules)); - - if (ApplicationManager.getApplication().isUnitTestMode()) { - LOG.error(message); + private fun showNotSpecifiedError(resourceId: @PropertyKey(resourceBundle = JavaCompilerBundle.BUNDLE) @NonNls String?, + notSpecifiedValueInheritedFromProject: Boolean, + modules: List, + editorNameToSelect: String) { + val nameToSelect = if (notSpecifiedValueInheritedFromProject) null else modules.first() + val message = JavaCompilerBundle.message(resourceId!!, modules.size, formatModulesList(modules)) + if (ApplicationManager.getApplication().isUnitTestMode) { + LOG.error(message) } - - CompileDriverNotifications.getInstance(myProject) + CompileDriverNotifications.getInstance(project) .createCannotStartNotification() .withContent(message) .withOpenSettingsAction(nameToSelect, editorNameToSelect) - .showNotification(); + .showNotification() + } +} + +private fun useBuildToolWindow(): Boolean { + return SystemProperties.getBooleanProperty("ide.jps.use.build.tool.window", true) +} + +private class BuildToolWindowActivationListener(compileContext: CompileContextImpl) : NotificationListener.Adapter() { + private val projectRef: WeakReference + private val contentId: Any + + init { + projectRef = WeakReference(compileContext.project) + contentId = compileContext.buildSession.contentId } - @NotNull - private static String formatModulesList(@NotNull List modules) { - final int maxModulesToShow = 10; - List actualNamesToInclude = new ArrayList<>(ContainerUtil.getFirstItems(modules, maxModulesToShow)); - if (modules.size() > maxModulesToShow) { - actualNamesToInclude.add(JavaCompilerBundle.message("error.jdk.module.names.overflow.element.ellipsis")); + override fun hyperlinkActivated(notification: Notification, e: HyperlinkEvent) { + val project = projectRef.get() + val useBuildToolwindow = useBuildToolWindow() + val toolWindowId = if (useBuildToolwindow) BuildContentManager.TOOL_WINDOW_ID else ToolWindowId.MESSAGES_WINDOW + if (project != null && !project.isDisposed && + (useBuildToolwindow || CompilerMessagesService.showCompilerContent(project, contentId))) { + ToolWindowManager.getInstance(project).getToolWindow(toolWindowId)?.activate(null, false) } - - return NlsMessages.formatNarrowAndList(actualNamesToInclude); - } - - public static CompilerMessageCategory convertToCategory(CmdlineRemoteProto.Message.BuilderMessage.CompileMessage.Kind kind, - CompilerMessageCategory defaultCategory) { - switch (kind) { - case ERROR: - case INTERNAL_BUILDER_ERROR: - return CompilerMessageCategory.ERROR; - case WARNING: - return CompilerMessageCategory.WARNING; - case INFO: - case JPS_INFO: - case OTHER: - return CompilerMessageCategory.INFORMATION; - default: - return defaultCategory; + else { + notification.expire() } } +} - private static final class BuildToolWindowActivationListener extends NotificationListener.Adapter { - private final WeakReference myProjectRef; - private final Object myContentId; +private fun isCompilationStartedAutomatically(scope: CompileScope): Boolean { + return java.lang.Boolean.TRUE == scope.getUserData(COMPILATION_STARTED_AUTOMATICALLY) +} - BuildToolWindowActivationListener(CompileContextImpl compileContext) { - myProjectRef = new WeakReference<>(compileContext.getProject()); - myContentId = compileContext.getBuildSession().getContentId(); - } +private fun getModulesString(modulesInChunk: Collection): String { + return modulesInChunk.joinToString(separator = "\n") { "\"" + it.name + "\"" } +} - @Override - protected void hyperlinkActivated(@NotNull Notification notification, @NotNull HyperlinkEvent e) { - Project project = myProjectRef.get(); - boolean useBuildToolwindow = useBuildToolWindow(); - String toolWindowId = useBuildToolwindow ? BuildContentManager.TOOL_WINDOW_ID : ToolWindowId.MESSAGES_WINDOW; - if (project != null && !project.isDisposed() && - (useBuildToolwindow || CompilerMessagesService.showCompilerContent(project, myContentId))) { - ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow(toolWindowId); - if (toolWindow != null) { - toolWindow.activate(null, false); +private fun hasSources(module: Module, rootType: JavaSourceRootType): Boolean { + return !ModuleRootManager.getInstance(module).getSourceRoots(rootType).isEmpty() +} + +private fun formatModulesList(modules: List): String { + val maxModulesToShow = 10 + val actualNamesToInclude: MutableList = ArrayList(ContainerUtil.getFirstItems(modules, maxModulesToShow)) + if (modules.size > maxModulesToShow) { + actualNamesToInclude.add(JavaCompilerBundle.message("error.jdk.module.names.overflow.element.ellipsis")) + } + return NlsMessages.formatNarrowAndList(actualNamesToInclude) +} + +private fun createStatusMessage(status: ExitStatus, warningCount: Int, errorCount: Int, duration: Long): @Nls String { + return when { + status === ExitStatus.CANCELLED -> JavaCompilerBundle.message("status.compilation.aborted") + status === ExitStatus.UP_TO_DATE -> JavaCompilerBundle.message("status.all.up.to.date") + else -> { + val durationString = NlsMessages.formatDurationApproximate(duration) + if (status === ExitStatus.SUCCESS) { + if (warningCount > 0) { + JavaCompilerBundle.message("status.compilation.completed.successfully.with.warnings", warningCount, durationString) + } + else { + JavaCompilerBundle.message("status.compilation.completed.successfully", durationString) } } else { - notification.expire(); + JavaCompilerBundle.message("status.compilation.completed.successfully.with.warnings.and.errors", + errorCount, warningCount, durationString) } } } - - private static boolean useBuildToolWindow() { - return SystemProperties.getBooleanProperty("ide.jps.use.build.tool.window", true); - } -} +} \ No newline at end of file diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompileScopeUtil.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompileScopeUtil.java index 81520b791682..74ee7aa2d204 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileScopeUtil.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileScopeUtil.java @@ -1,4 +1,4 @@ -// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.compiler.impl; import com.intellij.compiler.ModuleSourceSet; @@ -8,6 +8,7 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.packaging.artifacts.Artifact; import com.intellij.util.containers.ContainerUtil; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.jps.api.CmdlineProtoUtil; import org.jetbrains.jps.api.CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.TargetTypeBuildScope; @@ -101,9 +102,14 @@ public final class CompileScopeUtil { return scope.getUserData(BASE_SCOPE_FOR_EXTERNAL_BUILD); } - public static List mergeScopes(List scopes1, List scopes2) { - if (scopes2.isEmpty()) return scopes1; - if (scopes1.isEmpty()) return scopes2; + public static List mergeScopes(@NotNull List scopes1, + @NotNull List scopes2) { + if (scopes2.isEmpty()) { + return scopes1; + } + if (scopes1.isEmpty()) { + return scopes2; + } Map scopeById = new HashMap<>(); mergeScopes(scopeById, scopes1); @@ -145,8 +151,11 @@ public final class CompileScopeUtil { } public static boolean allProjectModulesAffected(CompileContextImpl compileContext) { - final Set allModules = ContainerUtil.set(compileContext.getProjectCompileScope().getAffectedModules()); - allModules.removeAll(Arrays.asList(compileContext.getCompileScope().getAffectedModules())); + @SuppressWarnings("SSBasedInspection") + Set allModules = new ObjectOpenHashSet<>(compileContext.getProjectCompileScope().getAffectedModules()); + for (Module module : compileContext.getCompileScope().getAffectedModules()) { + allModules.remove(module); + } return allModules.isEmpty(); } diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompilerErrorTreeView.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompilerErrorTreeView.java index edc6d4beabb3..afa8435bb707 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompilerErrorTreeView.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompilerErrorTreeView.java @@ -1,4 +1,4 @@ -// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.compiler.impl; import com.intellij.codeInsight.daemon.impl.actions.SuppressFix; @@ -25,20 +25,20 @@ import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class CompilerErrorTreeView extends NewErrorTreeViewPanel { +public final class CompilerErrorTreeView extends NewErrorTreeViewPanel { public CompilerErrorTreeView(Project project, Runnable rerunAction) { super(project, null, true, true, rerunAction); } @Override - protected void fillRightToolbarGroup(DefaultActionGroup group) { + protected void fillRightToolbarGroup(@NotNull DefaultActionGroup group) { super.fillRightToolbarGroup(group); group.addSeparator(); group.add(new CompilerPropertiesAction()); } @Override - protected void addExtraPopupMenuActions(DefaultActionGroup group) { + protected void addExtraPopupMenuActions(@NotNull DefaultActionGroup group) { group.addSeparator(); group.add(new ExcludeFromCompileAction(myProject) { @Override @@ -62,11 +62,10 @@ public class CompilerErrorTreeView extends NewErrorTreeViewPanel { } @Override - protected ErrorViewStructure createErrorViewStructure(Project project, boolean canHideWarnings) { + protected @NotNull ErrorViewStructure createErrorViewStructure(Project project, boolean canHideWarnings) { return new ErrorViewStructure(project, canHideWarnings) { - @NotNull @Override - protected GroupingElement createGroupingElement(String groupName, Object data, VirtualFile file) { + protected @NotNull GroupingElement createGroupingElement(String groupName, Object data, VirtualFile file) { return new GroupingElement(groupName, data, file) { @Override public boolean isRenderWithBoldFont() { @@ -79,7 +78,7 @@ public class CompilerErrorTreeView extends NewErrorTreeViewPanel { private class SuppressJavacWarningsAction extends AnAction { @Override - public void actionPerformed(@NotNull final AnActionEvent e) { + public void actionPerformed(final @NotNull AnActionEvent e) { final NavigatableMessageElement messageElement = (NavigatableMessageElement)getSelectedErrorTreeElement(); final String[] text = messageElement.getText(); final String id = text[0].substring(1, text[0].indexOf("]")); @@ -100,7 +99,7 @@ public class CompilerErrorTreeView extends NewErrorTreeViewPanel { } @Override - public void update(@NotNull final AnActionEvent e) { + public void update(final @NotNull AnActionEvent e) { final Presentation presentation = e.getPresentation(); presentation.setEnabledAndVisible(false); final Project project = e.getProject(); @@ -151,29 +150,29 @@ public class CompilerErrorTreeView extends NewErrorTreeViewPanel { } } - protected SuppressFix getSuppressAction(@NotNull final String id) { + protected SuppressFix getSuppressAction(final @NotNull String id) { return new SuppressFix(id) { @Override @SuppressWarnings({"SimplifiableIfStatement"}) - public boolean isAvailable(@NotNull final Project project, @NotNull final PsiElement context) { + public boolean isAvailable(final @NotNull Project project, final @NotNull PsiElement context) { if (getContainer(context) instanceof PsiClass) return false; return super.isAvailable(project, context); } @Override - protected boolean use15Suppressions(@NotNull final PsiJavaDocumentedElement container) { + protected boolean use15Suppressions(final @NotNull PsiJavaDocumentedElement container) { return true; } }; } } - private class SuppressJavacWarningForClassAction extends SuppressJavacWarningsAction { + private final class SuppressJavacWarningForClassAction extends SuppressJavacWarningsAction { @Override - protected SuppressFix getSuppressAction(@NotNull final String id) { + protected SuppressFix getSuppressAction(final @NotNull String id) { return new SuppressForClassFix(id){ @Override - protected boolean use15Suppressions(@NotNull final PsiJavaDocumentedElement container) { + protected boolean use15Suppressions(final @NotNull PsiJavaDocumentedElement container) { return true; } }; diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompilerUtil.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompilerUtil.java index 88e9d5556ba5..c84712a2d3eb 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompilerUtil.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompilerUtil.java @@ -1,4 +1,4 @@ -// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.compiler.impl; import com.intellij.openapi.compiler.CompileContext; @@ -19,32 +19,15 @@ import java.io.File; import java.util.Collection; import java.util.HashSet; -/** - * @author Jeka - */ public final class CompilerUtil { private static final Logger LOG = Logger.getInstance(CompilerUtil.class); - public static String quotePath(String path) { - if (path != null && path.indexOf(' ') != -1) { - path = path.replaceAll("\\\\", "\\\\\\\\"); - path = '"' + path + '"'; - } - return path; - } - public static void refreshIOFiles(@NotNull final Collection files) { if (!files.isEmpty()) { LocalFileSystem.getInstance().refreshIoFiles(files); } } - public static void refreshIODirectories(@NotNull final Collection files) { - if (!files.isEmpty()) { - LocalFileSystem.getInstance().refreshIoFiles(files, false, true, null); - } - } - /** * A lightweight procedure which ensures that given roots exist in the VFS. * No actual refresh is performed. @@ -73,13 +56,6 @@ public final class CompilerUtil { } } - public static void refreshIOFile(final File file) { - final VirtualFile vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file); - if (vFile != null) { - vFile.refresh(false, false); - } - } - public static void runInContext(CompileContext context, @NlsContexts.ProgressText String title, ThrowableRunnable action) throws T { ProgressIndicator indicator = context.getProgressIndicator(); if (title != null) { diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/ProblemsViewImpl.kt b/java/compiler/impl/src/com/intellij/compiler/impl/ProblemsViewImpl.kt index 49fc44820bf0..1a833f54e32b 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/ProblemsViewImpl.kt +++ b/java/compiler/impl/src/com/intellij/compiler/impl/ProblemsViewImpl.kt @@ -1,171 +1,222 @@ // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.compiler.impl; +package com.intellij.compiler.impl -import com.intellij.compiler.ProblemsView; -import com.intellij.icons.AllIcons; -import com.intellij.ide.IdeBundle; -import com.intellij.ide.errorTreeView.ErrorTreeElement; -import com.intellij.ide.errorTreeView.ErrorTreeElementKind; -import com.intellij.ide.errorTreeView.ErrorViewStructure; -import com.intellij.ide.errorTreeView.GroupingElement; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.compiler.CompileScope; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.wm.ToolWindow; -import com.intellij.openapi.wm.ToolWindowManager; -import com.intellij.pom.Navigatable; -import com.intellij.ui.content.Content; -import com.intellij.ui.content.ContentFactory; -import com.intellij.util.concurrency.SequentialTaskExecutor; -import kotlin.Unit; -import org.jetbrains.annotations.Nls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import com.intellij.compiler.ProblemsView +import com.intellij.icons.AllIcons +import com.intellij.ide.IdeBundle +import com.intellij.ide.errorTreeView.ErrorTreeElementKind +import com.intellij.ide.errorTreeView.ErrorViewStructure +import com.intellij.ide.errorTreeView.GroupingElement +import com.intellij.ide.errorTreeView.NewErrorTreeViewPanel +import com.intellij.openapi.actionSystem.DefaultActionGroup +import com.intellij.openapi.application.* +import com.intellij.openapi.compiler.CompileScope +import com.intellij.openapi.compiler.JavaCompilerBundle +import com.intellij.openapi.fileEditor.OpenFileDescriptor +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Disposer +import com.intellij.openapi.wm.ToolWindow +import com.intellij.openapi.wm.ToolWindowFactory +import com.intellij.openapi.wm.ToolWindowManager +import com.intellij.pom.Navigatable +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.debounce +import org.jetbrains.annotations.Nls +import java.util.* +import javax.swing.Icon +import kotlin.time.Duration.Companion.milliseconds -import java.util.EnumSet; -import java.util.UUID; -import java.util.concurrent.ExecutorService; +private const val AUTO_BUILD_TOOLWINDOW_ID = "Problems" -@SuppressWarnings("IncorrectParentDisposable") -final class ProblemsViewImpl extends ProblemsView { - private static final String AUTO_BUILD_TOOLWINDOW_ID = "Problems"; +private val interestingMessageKinds = EnumSet.of(ErrorTreeElementKind.ERROR, ErrorTreeElementKind.WARNING, ErrorTreeElementKind.NOTE) - private volatile ProblemsViewPanel myPanel; - private final ExecutorService myViewUpdater = SequentialTaskExecutor.createSequentialApplicationPoolExecutor("ProblemsView Pool"); - private static final EnumSet interestingMessageKinds = - EnumSet.of(ErrorTreeElementKind.ERROR, ErrorTreeElementKind.WARNING, ErrorTreeElementKind.NOTE); +@OptIn(FlowPreview::class) +internal class ProblemsViewImpl(project: Project) : ProblemsView(project) { + @Volatile + private var panel: ProblemsViewPanel? = null - ProblemsViewImpl(@NotNull Project project) { - super(project); + @OptIn(ExperimentalCoroutinesApi::class) + private val messageScope = createSupervisorCoroutineScope(project.coroutineScope, Dispatchers.Default.limitedParallelism(1)) - Disposer.register(project, myViewUpdater::shutdownNow); - myViewUpdater.execute(() -> { - ApplicationManager.getApplication().invokeAndWait(() -> { - if (project.isDisposed()) { - return; - } + private val state = NewErrorTreeViewPanel.MessageViewState() + private val errorViewStructure = ErrorViewStructure(project, /* canHideWarnings = */ false) - ProblemsViewPanel panel = new ProblemsViewPanel(project); + private val iconFlow = MutableStateFlow(AllIcons.Toolwindows.ProblemsEmpty) - ToolWindow toolWindow = ToolWindowManager.getInstance(project).registerToolWindow(AUTO_BUILD_TOOLWINDOW_ID, builder -> { - builder.icon = AllIcons.Toolwindows.ProblemsEmpty; - builder.stripeTitle = IdeBundle.messagePointer("toolwindow.stripe.Problems"); - builder.canCloseContent = false; - return Unit.INSTANCE; - }); - Disposer.register(toolWindow.getDisposable(), panel); + init { + val toolWindowManager = ToolWindowManager.getInstance(project) + toolWindowManager.invokeLater(Runnable { + val toolWindow = toolWindowManager.registerToolWindow(AUTO_BUILD_TOOLWINDOW_ID) { + icon = getEffectiveIcon() + stripeTitle = IdeBundle.messagePointer("toolwindow.stripe.Problems") + canCloseContent = false + @Suppress("ObjectLiteralToLambda") + contentFactory = object : ToolWindowFactory { + override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) { + val panel = ProblemsViewPanel(project = project, state = state, errorViewStructure = errorViewStructure) + Disposer.register(toolWindow.disposable, panel) + this@ProblemsViewImpl.panel = panel - Content content = ContentFactory.getInstance().createContent(panel, "", false); - content.setHelpId("reference.problems.tool.window"); - toolWindow.getContentManager().addContent(content); - - doUpdateIcon(panel, toolWindow); - - myPanel = panel; - }, ModalityState.NON_MODAL); - }); - } - - @Override - public void clearOldMessages(@Nullable CompileScope scope, @NotNull UUID currentSessionId) { - myViewUpdater.execute(() -> { - cleanupChildrenRecursively(myPanel.getErrorViewStructure().getRootElement(), scope, currentSessionId); - updateIcon(); - myPanel.reload(); - }); - } - - private void cleanupChildrenRecursively(@NotNull final Object fromElement, final @Nullable CompileScope scope, @NotNull UUID currentSessionId) { - final ErrorViewStructure structure = myPanel.getErrorViewStructure(); - for (ErrorTreeElement element : structure.getChildElements(fromElement)) { - if (element instanceof GroupingElement) { - if (scope != null) { - final VirtualFile file = ((GroupingElement)element).getFile(); - if (file != null && !scope.belongs(file.getUrl())) { - continue; + val contentManager = toolWindow.contentManager + val content = contentManager.factory.createContent(panel, "", false) + content.helpId = "reference.problems.tool.window" + contentManager.addContent(content) } } - if (!currentSessionId.equals(element.getData())) { - structure.removeElement(element); + } + + project.coroutineScope.launch { + iconFlow + .debounce(100.milliseconds) + .collectLatest { icon -> + withContext(Dispatchers.EDT) { + toolWindow.setIcon(icon) + } + } + } + }) + } + + private fun getEffectiveIcon(): Icon { + return if (errorViewStructure.hasMessages(interestingMessageKinds)) { + AllIcons.Toolwindows.Problems + } + else { + AllIcons.Toolwindows.ProblemsEmpty + } + } + + override fun clearOldMessages(scope: CompileScope?, currentSessionId: UUID) { + messageScope.launch { + cleanupChildrenRecursively(errorViewStructure.rootElement, scope, currentSessionId) + panel?.reload() + iconFlow.value = getEffectiveIcon() + } + } + + override fun addMessage(type: Int, + text: Array, + groupName: String?, + navigatable: Navigatable?, + exportTextPrefix: String?, + rendererTextPrefix: String?, + sessionId: UUID) { + messageScope.launch { + val structure = errorViewStructure + val group = structure.lookupGroupingElement(groupName) + if (group != null && sessionId != group.data) { + structure.removeElement(group) + } + + val kind = ErrorTreeElementKind.convertMessageFromCompilerErrorType(type) + val element = if (navigatable == null) { + errorViewStructure.addMessage( + /* kind = */ kind, + /* text = */ text, + /* underFileGroup = */ null, + /* file = */ null, + /* line = */ -1, + /* column = */ -1, + /* data = */ sessionId + ) + } + else { + errorViewStructure.addNavigatableMessage( + /* groupName = */ groupName, + /* navigatable = */ navigatable, + /* kind = */ kind, + /* message = */ text, + /* data = */ sessionId, + /* exportText = */ exportTextPrefix ?: "", + /* rendererTextPrefix = */ rendererTextPrefix ?: "", + /* file = */ (navigatable as? OpenFileDescriptor)?.file + ) + } + panel?.updateAddedElement(element) + + iconFlow.value = if (interestingMessageKinds.contains(kind) || errorViewStructure.hasMessages(interestingMessageKinds)) { + AllIcons.Toolwindows.Problems + } + else { + AllIcons.Toolwindows.ProblemsEmpty + } + } + } + + override fun setProgress(text: @Nls String?, fraction: Float) { + state.progressText = text + state.fraction = fraction + panel?.updateProgress() + } + + override fun setProgress(text: @Nls String?) { + state.progressText = text + panel?.updateProgress() + } + + override fun clearProgress() { + state.clearProgress() + panel?.updateProgress() + } + + private fun cleanupChildrenRecursively(fromElement: Any, scope: CompileScope?, currentSessionId: UUID) { + for (element in errorViewStructure.getChildElements(fromElement)) { + if (element is GroupingElement) { + if (scope != null) { + val file = element.file + if (file != null && !scope.belongs(file.url)) { + continue + } + } + if (currentSessionId != element.getData()) { + errorViewStructure.removeElement(element) } else { - cleanupChildrenRecursively(element, scope, currentSessionId); + cleanupChildrenRecursively(element, scope, currentSessionId) } } - else { - if (!currentSessionId.equals(element.getData())) { - structure.removeElement(element); - } + else if (currentSessionId != element.data) { + errorViewStructure.removeElement(element) } } } - - @Override - public void addMessage(int type, - String @NotNull [] text, - @Nullable String groupName, - @Nullable Navigatable navigatable, - @Nullable String exportTextPrefix, @Nullable String rendererTextPrefix, @Nullable UUID sessionId) { - myViewUpdater.execute(() -> { - final ErrorViewStructure structure = myPanel.getErrorViewStructure(); - final GroupingElement group = structure.lookupGroupingElement(groupName); - if (group != null && sessionId != null && !sessionId.equals(group.getData())) { - structure.removeElement(group); - } - if (navigatable != null) { - myPanel.addMessage(type, text, groupName, navigatable, exportTextPrefix, rendererTextPrefix, sessionId); - } - else { - myPanel.addMessage(type, text, null, -1, -1, sessionId); - } - updateIcon(); - }); - } - - private void updateIcon() { - ApplicationManager.getApplication().invokeLater(() -> { - ToolWindow toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(AUTO_BUILD_TOOLWINDOW_ID); - if (toolWindow != null) { - doUpdateIcon(myPanel, toolWindow); - } - }, myProject.getDisposed()); - } - - private static void doUpdateIcon(@NotNull ProblemsViewPanel panel, @NotNull ToolWindow toolWindow) { - boolean active = panel.getErrorViewStructure().hasMessages(interestingMessageKinds); - toolWindow.setIcon(active ? AllIcons.Toolwindows.Problems : AllIcons.Toolwindows.ProblemsEmpty); - } - - @Override - public void setProgress(@Nls String text, float fraction) { - ProblemsViewPanel panel = myPanel; - if (panel == null) { - myViewUpdater.execute(() -> myPanel.setProgress(text, fraction)); - } - else { - panel.setProgress(text, fraction); - } - } - - @Override - public void setProgress(@Nls String text) { - ProblemsViewPanel panel = myPanel; - if (panel == null) { - myViewUpdater.execute(() -> myPanel.setProgressText(text)); - } - else { - panel.setProgressText(text); - } - } - - @Override - public void clearProgress() { - ProblemsViewPanel panel = myPanel; - if (panel != null) { - panel.clearProgressData(); - } - } } + +class ProblemsViewPanel(project: Project, state: MessageViewState, errorViewStructure: ErrorViewStructure?) + : NewErrorTreeViewPanel(myProject = project, + helpId = null, + createExitAction = false, + state = state, + errorViewStructure = errorViewStructure) { + constructor(project: Project) : this(project, MessageViewState(), null) + + init { + myTree.emptyText.text = JavaCompilerBundle.message("no.compilation.problems.found") + // hack: this will pre-initialize progress UI + updateProgress() + } + + override fun fillRightToolbarGroup(group: DefaultActionGroup) { + super.fillRightToolbarGroup(group) + + group.addSeparator() + group.add(CompilerPropertiesAction()) + } + + override fun addExtraPopupMenuActions(group: DefaultActionGroup) { + group.add(object : ExcludeFromCompileAction(myProject) { + override fun getFile() = selectedFile + }) + // todo: do we need compiler's popup actions here? + //ActionGroup popupGroup = (ActionGroup)ActionManager.getInstance().getAction(IdeActions.GROUP_COMPILER_ERROR_VIEW_POPUP); + //if (popupGroup != null) { + // for (AnAction action : popupGroup.getChildren(null)) { + // group.add(action); + // } + //} + } + + override fun canHideWarnings() = false +} \ No newline at end of file diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/ProblemsViewPanel.java b/java/compiler/impl/src/com/intellij/compiler/impl/ProblemsViewPanel.java deleted file mode 100644 index 92b752ef8342..000000000000 --- a/java/compiler/impl/src/com/intellij/compiler/impl/ProblemsViewPanel.java +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package com.intellij.compiler.impl; - -import com.intellij.ide.errorTreeView.NewErrorTreeViewPanel; -import com.intellij.openapi.actionSystem.DefaultActionGroup; -import com.intellij.openapi.compiler.JavaCompilerBundle; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public final class ProblemsViewPanel extends NewErrorTreeViewPanel { - public ProblemsViewPanel(@NotNull Project project) { - super(project, null, false, true, null); - - myTree.getEmptyText().setText(JavaCompilerBundle.message("no.compilation.problems.found")); - setProgress("", 0.0f); // hack: this will pre-initialize progress UI - } - - @Override - protected void fillRightToolbarGroup(DefaultActionGroup group) { - super.fillRightToolbarGroup(group); - group.addSeparator(); - group.add(new CompilerPropertiesAction()); - } - - @Override - protected void addExtraPopupMenuActions(DefaultActionGroup group) { - group.add(new ExcludeFromCompileAction(myProject) { - @Override - protected @Nullable VirtualFile getFile() { - return getSelectedFile(); - } - }); - // todo: do we need compiler's popup actions here? - //ActionGroup popupGroup = (ActionGroup)ActionManager.getInstance().getAction(IdeActions.GROUP_COMPILER_ERROR_VIEW_POPUP); - //if (popupGroup != null) { - // for (AnAction action : popupGroup.getChildren(null)) { - // group.add(action); - // } - //} - } - - @Override - protected boolean canHideWarnings() { - return false; - } -} \ No newline at end of file diff --git a/java/compiler/impl/src/com/intellij/compiler/progress/CompilerTask.java b/java/compiler/impl/src/com/intellij/compiler/progress/CompilerTask.java index 1f6ec9341bc0..b6f948a6f609 100644 --- a/java/compiler/impl/src/com/intellij/compiler/progress/CompilerTask.java +++ b/java/compiler/impl/src/com/intellij/compiler/progress/CompilerTask.java @@ -11,7 +11,6 @@ import com.intellij.openapi.compiler.CompilerMessageCategory; import com.intellij.openapi.compiler.JavaCompilerBundle; import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.progress.*; -import com.intellij.openapi.progress.impl.CoreProgressManager; import com.intellij.openapi.progress.util.AbstractProgressIndicatorExBase; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.NlsContexts; @@ -27,7 +26,6 @@ import com.intellij.util.SystemProperties; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; @@ -260,10 +258,10 @@ public final class CompilerTask extends Task.Backgroundable { ProgressManager.getInstance().run(this); } - public @NotNull CompletableFuture startAsync(Runnable compileWork, Runnable restartWork) { + public void runUsingCurrentIndicator(Runnable compileWork, Runnable restartWork) { myCompileWork = compileWork; myRestartWork = restartWork; - return (CompletableFuture)((CoreProgressManager)ProgressManager.getInstance()).runProcessWithProgressAsynchronously(this); + run(ProgressManager.getInstance().getProgressIndicator()); } public void run(Runnable compileWork, Runnable restartWork, ProgressIndicator progressIndicator) { diff --git a/java/compiler/impl/src/com/intellij/compiler/server/AutoMakeMessageHandler.kt b/java/compiler/impl/src/com/intellij/compiler/server/AutoMakeMessageHandler.kt index e6c2285a4272..6adc395c0ea6 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/AutoMakeMessageHandler.kt +++ b/java/compiler/impl/src/com/intellij/compiler/server/AutoMakeMessageHandler.kt @@ -1,213 +1,201 @@ -// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package com.intellij.compiler.server; +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.compiler.server -import com.intellij.compiler.CompilerMessageImpl; -import com.intellij.compiler.ProblemsView; -import com.intellij.compiler.impl.CompileDriver; -import com.intellij.notification.Notification; -import com.intellij.openapi.application.ReadAction; -import com.intellij.openapi.compiler.*; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.MessageType; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileManager; -import com.intellij.problems.Problem; -import com.intellij.problems.WolfTheProblemSolver; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jps.api.CmdlineRemoteProto; -import org.jetbrains.jps.api.GlobalOptions; +import com.intellij.compiler.CompilerMessageImpl +import com.intellij.compiler.ProblemsView +import com.intellij.compiler.impl.CompileDriver.Companion.convertToCategory +import com.intellij.notification.Notification +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.compiler.CompilerManager +import com.intellij.openapi.compiler.CompilerMessageCategory +import com.intellij.openapi.compiler.CompilerTopics +import com.intellij.openapi.compiler.JavaCompilerBundle +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.MessageType +import com.intellij.openapi.util.Key +import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.openapi.vfs.VirtualFileManager +import com.intellij.problems.WolfTheProblemSolver +import org.jetbrains.jps.api.CmdlineRemoteProto +import org.jetbrains.jps.api.CmdlineRemoteProto.Message.BuilderMessage +import org.jetbrains.jps.api.GlobalOptions +import java.awt.EventQueue +import java.util.* -import javax.swing.*; -import java.util.Collections; -import java.util.UUID; +private val LAST_AUTO_MAKE_NOTIFICATION = Key.create("LAST_AUTO_MAKE_NOTIFICATION") /** -* @author Eugene Zhuravlev -*/ -class AutoMakeMessageHandler extends DefaultMessageHandler { - private static final Key LAST_AUTO_MAKE_NOTIFICATION = Key.create("LAST_AUTO_MAKE_NOTIFICATION"); - private CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status myBuildStatus; - private final Project myProject; - private final WolfTheProblemSolver myWolf; - private volatile boolean myUnprocessedFSChangesDetected = false; - private final AutomakeCompileContext myContext; + * @author Eugene Zhuravlev + */ +internal class AutoMakeMessageHandler(private val project: Project) : DefaultMessageHandler(project) { + private var buildStatus: BuilderMessage.BuildEvent.Status = BuilderMessage.BuildEvent.Status.SUCCESS + private val wolf: WolfTheProblemSolver = WolfTheProblemSolver.getInstance(project) - AutoMakeMessageHandler(@NotNull Project project) { - super(project); - myProject = project; - myBuildStatus = CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status.SUCCESS; - myWolf = WolfTheProblemSolver.getInstance(project); - myContext = new AutomakeCompileContext(project); - myContext.getProgressIndicator().start(); + @Volatile + private var isUnprocessedFsChangesDetected = false + private val context = AutomakeCompileContext(project) + + private val problemView by lazy(LazyThreadSafetyMode.NONE) { ProblemsView.getInstance(project) } + + init { + context.progressIndicator.start() } - public boolean unprocessedFSChangesDetected() { - return myUnprocessedFSChangesDetected; - } + fun unprocessedFSChangesDetected() = isUnprocessedFsChangesDetected - @Override - protected void handleBuildEvent(UUID sessionId, CmdlineRemoteProto.Message.BuilderMessage.BuildEvent event) { - if (myProject.isDisposed()) { - return; + override fun handleBuildEvent(sessionId: UUID, event: BuilderMessage.BuildEvent) { + if (project.isDisposed) { + return } - switch (event.getEventType()) { - case BUILD_COMPLETED: - myContext.getProgressIndicator().stop(); + + when (event.eventType) { + BuilderMessage.BuildEvent.Type.BUILD_COMPLETED -> { + context.progressIndicator.stop() if (event.hasCompletionStatus()) { - final CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status status = event.getCompletionStatus(); - myBuildStatus = status; - if (status == CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Status.CANCELED) { - myContext.getProgressIndicator().cancel(); + val status = event.completionStatus + buildStatus = status + if (status == BuilderMessage.BuildEvent.Status.CANCELED) { + context.progressIndicator.cancel() } } - final int errors = myContext.getMessageCount(CompilerMessageCategory.ERROR); - final int warnings = myContext.getMessageCount(CompilerMessageCategory.WARNING); - //noinspection SSBasedInspection - SwingUtilities.invokeLater(() -> { - if (myProject.isDisposed()) { - return; + + val errors = context.getMessageCount(CompilerMessageCategory.ERROR) + val warnings = context.getMessageCount(CompilerMessageCategory.WARNING) + EventQueue.invokeLater { + if (project.isDisposed) { + return@invokeLater } - final CompilationStatusListener publisher = myProject.getMessageBus().syncPublisher(CompilerTopics.COMPILATION_STATUS); - publisher.automakeCompilationFinished(errors, warnings, myContext); - }); - return; - - case FILES_GENERATED: - final CompilationStatusListener publisher = myProject.getMessageBus().syncPublisher(CompilerTopics.COMPILATION_STATUS); - for (CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.GeneratedFile generatedFile : event.getGeneratedFilesList()) { - final String root = FileUtil.toSystemIndependentName(generatedFile.getOutputRoot()); - final String relativePath = FileUtil.toSystemIndependentName(generatedFile.getRelativePath()); - publisher.fileGenerated(root, relativePath); + val publisher = project.messageBus.syncPublisher(CompilerTopics.COMPILATION_STATUS) + publisher.automakeCompilationFinished(errors, warnings, context) } - return; - - case CUSTOM_BUILDER_MESSAGE: - if (event.hasCustomBuilderMessage()) { - final CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.CustomBuilderMessage message = event.getCustomBuilderMessage(); - if (GlobalOptions.JPS_SYSTEM_BUILDER_ID.equals(message.getBuilderId()) && GlobalOptions.JPS_UNPROCESSED_FS_CHANGES_MESSAGE_ID.equals(message.getMessageType())) { - myUnprocessedFSChangesDetected = true; - } - } - return; - - default: + } + BuilderMessage.BuildEvent.Type.FILES_GENERATED -> { + val publisher = project.messageBus.syncPublisher(CompilerTopics.COMPILATION_STATUS) + for (generatedFile in event.generatedFilesList) { + val root = FileUtil.toSystemIndependentName(generatedFile.outputRoot) + val relativePath = FileUtil.toSystemIndependentName(generatedFile.relativePath) + publisher.fileGenerated(root, relativePath) + } + } + BuilderMessage.BuildEvent.Type.CUSTOM_BUILDER_MESSAGE -> { + if (event.hasCustomBuilderMessage()) { + val message = event.customBuilderMessage + if (GlobalOptions.JPS_SYSTEM_BUILDER_ID == message.builderId && GlobalOptions.JPS_UNPROCESSED_FS_CHANGES_MESSAGE_ID == message.messageType) { + isUnprocessedFsChangesDetected = true + } + } + } + else -> {} } } - @Override - protected void handleCompileMessage(final UUID sessionId, CmdlineRemoteProto.Message.BuilderMessage.CompileMessage message) { - if (myProject.isDisposed()) { - return; + override fun handleCompileMessage(sessionId: UUID, message: BuilderMessage.CompileMessage) { + if (project.isDisposed) { + return } - final CmdlineRemoteProto.Message.BuilderMessage.CompileMessage.Kind kind = message.getKind(); - if (kind == CmdlineRemoteProto.Message.BuilderMessage.CompileMessage.Kind.PROGRESS) { - final ProblemsView view = ProblemsView.getInstance(myProject); + + val kind = message.kind + if (kind == BuilderMessage.CompileMessage.Kind.PROGRESS) { if (message.hasDone()) { - view.setProgress(message.getText(), message.getDone()); + problemView.setProgress(message.text, message.done) } else { - view.setProgress(message.getText()); + problemView.setProgress(message.text) } } else { - final CompilerMessageCategory category = CompileDriver.convertToCategory(kind, null); - if (category != null) { // only process supported kinds of messages - final String sourceFilePath = message.hasSourceFilePath() ? message.getSourceFilePath() : null; - final String url = sourceFilePath != null ? VirtualFileManager.constructUrl(LocalFileSystem.PROTOCOL, FileUtil.toSystemIndependentName(sourceFilePath)) : null; - final long line = message.hasLine() ? message.getLine() : -1; - final long column = message.hasColumn() ? message.getColumn() : -1; - //noinspection HardCodedStringLiteral - final CompilerMessage msg = myContext.createAndAddMessage(category, message.getText(), url, (int)line, (int)column, null, message.getModuleNamesList()); - if (category == CompilerMessageCategory.ERROR || kind == CmdlineRemoteProto.Message.BuilderMessage.CompileMessage.Kind.JPS_INFO) { - if (category == CompilerMessageCategory.ERROR) { - ReadAction.run(() -> informWolf(message)); - } - if (msg != null) { - ProblemsView.getInstance(myProject).addMessage(msg, sessionId); - } + val category = convertToCategory(kind) ?: return + // only process supported kinds of messages + val sourceFilePath = if (message.hasSourceFilePath()) message.sourceFilePath else null + val url = if (sourceFilePath == null) { + null + } + else { + VirtualFileManager.constructUrl(LocalFileSystem.PROTOCOL, FileUtil.toSystemIndependentName(sourceFilePath)) + } + + val line = if (message.hasLine()) message.line else -1 + val column = if (message.hasColumn()) message.column else -1 + val compilerMessage = context + .createAndAddMessage(category, message.text, url, line.toInt(), column.toInt(), null, message.moduleNamesList) + if (category === CompilerMessageCategory.ERROR || kind == BuilderMessage.CompileMessage.Kind.JPS_INFO) { + if (category === CompilerMessageCategory.ERROR) { + informWolf(message) + } + if (compilerMessage != null) { + problemView.addMessage(compilerMessage, sessionId) } } } } - @Override - public void handleFailure(@NotNull UUID sessionId, CmdlineRemoteProto.Message.Failure failure) { - if (myProject.isDisposed()) { - return; + override fun handleFailure(sessionId: UUID, failure: CmdlineRemoteProto.Message.Failure) { + if (project.isDisposed) { + return } - String descr = failure.hasDescription() ? failure.getDescription() : null; - if (descr == null) { - descr = failure.hasStacktrace()? failure.getStacktrace() : ""; - } - final String msg = JavaCompilerBundle.message("notification.compiler.auto.build.failure", descr); - CompilerManager.NOTIFICATION_GROUP.createNotification(msg, MessageType.INFO).notify(myProject); - ProblemsView.getInstance(myProject).addMessage(new CompilerMessageImpl(myProject, CompilerMessageCategory.ERROR, msg), sessionId); + + val description = (if (failure.hasDescription()) failure.description else null) + ?: if (failure.hasStacktrace()) failure.stacktrace else "" + val message = JavaCompilerBundle.message("notification.compiler.auto.build.failure", description) + CompilerManager.NOTIFICATION_GROUP.createNotification(message, MessageType.INFO).notify(project) + problemView.addMessage(CompilerMessageImpl(project, CompilerMessageCategory.ERROR, message), sessionId) } - @Override - public void sessionTerminated(@NotNull UUID sessionId) { - String statusMessage = null/*"Auto make completed"*/; - switch (myBuildStatus) { - case SUCCESS: - //statusMessage = "Auto make completed successfully"; - break; - case UP_TO_DATE: - //statusMessage = "All files are up-to-date"; - break; - case ERRORS: - statusMessage = JavaCompilerBundle.message("notification.compiler.auto.build.completed.with.errors"); - break; - case CANCELED: - //statusMessage = "Auto make has been canceled"; - break; + override fun sessionTerminated(sessionId: UUID) { + var statusMessage: String? = null /*"Auto make completed"*/ + when (buildStatus) { + BuilderMessage.BuildEvent.Status.SUCCESS -> {} + BuilderMessage.BuildEvent.Status.UP_TO_DATE -> {} + BuilderMessage.BuildEvent.Status.ERRORS -> statusMessage = JavaCompilerBundle.message( + "notification.compiler.auto.build.completed.with.errors") + BuilderMessage.BuildEvent.Status.CANCELED -> {} } if (statusMessage != null) { - final Notification notification = CompilerManager.NOTIFICATION_GROUP.createNotification(statusMessage, MessageType.INFO); - if (!myProject.isDisposed()) { - notification.notify(myProject); + val notification = CompilerManager.NOTIFICATION_GROUP.createNotification(statusMessage, MessageType.INFO) + if (!project.isDisposed) { + notification.notify(project) } - myProject.putUserData(LAST_AUTO_MAKE_NOTIFICATION, notification); + project.putUserData(LAST_AUTO_MAKE_NOTIFICATION, notification) } else { - Notification notification = myProject.getUserData(LAST_AUTO_MAKE_NOTIFICATION); + val notification = project.getUserData(LAST_AUTO_MAKE_NOTIFICATION) if (notification != null) { - notification.expire(); - myProject.putUserData(LAST_AUTO_MAKE_NOTIFICATION, null); + notification.expire() + project.putUserData(LAST_AUTO_MAKE_NOTIFICATION, null) } } - if (!myProject.isDisposed()) { - ProblemsView view = ProblemsView.getInstanceIfCreated(myProject); - if (view != null) { - view.clearProgress(); - view.clearOldMessages(null, sessionId); + if (!project.isDisposed) { + ProblemsView.getInstanceIfCreated(project)?.let { view -> + view.clearProgress() + view.clearOldMessages(null, sessionId) } } } - @Override - public @NotNull ProgressIndicator getProgressIndicator() { - return myContext.getProgressIndicator(); - } + override fun getProgressIndicator() = context.progressIndicator - private void informWolf(CmdlineRemoteProto.Message.BuilderMessage.@NotNull CompileMessage message) { - final String srcPath = message.getSourceFilePath(); - if (srcPath != null && !myProject.isDisposed()) { - final VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(srcPath); - if (vFile != null) { - final int line = (int)message.getLine(); - final int column = (int)message.getColumn(); - if (line > 0 && column > 0) { - final Problem problem = myWolf.convertToProblem(vFile, line, column, new String[]{message.getText()}); - myWolf.weHaveGotProblems(vFile, Collections.singletonList(problem)); - } - else { - myWolf.queue(vFile); - } + private fun informWolf(message: BuilderMessage.CompileMessage) { + val srcPath = message.sourceFilePath ?: return + if (project.isDisposed) { + return + } + + ApplicationManager.getApplication().runReadAction { + if (project.isDisposed) { + return@runReadAction + } + + val vFile = LocalFileSystem.getInstance().findFileByPath(srcPath) ?: return@runReadAction + val line = message.line.toInt() + val column = message.column.toInt() + if (line > 0 && column > 0) { + val problem = wolf.convertToProblem(vFile, line, column, arrayOf(message.text)) + wolf.weHaveGotProblems(vFile, listOf(problem)) + } + else { + wolf.queue(vFile) } } } -} +} \ No newline at end of file diff --git a/java/compiler/impl/src/com/intellij/compiler/server/PreloadedProcessMessageHandler.java b/java/compiler/impl/src/com/intellij/compiler/server/PreloadedProcessMessageHandler.java index 83706fef3c66..469f7cd5e3bb 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/PreloadedProcessMessageHandler.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/PreloadedProcessMessageHandler.java @@ -1,24 +1,10 @@ -/* - * Copyright 2000-2014 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.compiler.server; /** * @author Eugene Zhuravlev */ -class PreloadedProcessMessageHandler extends DelegatingMessageHandler { +final class PreloadedProcessMessageHandler extends DelegatingMessageHandler { private volatile BuilderMessageHandler myDelegateHandler; PreloadedProcessMessageHandler() { diff --git a/java/compiler/openapi/resources/messages/JavaCompilerBundle.properties b/java/compiler/openapi/resources/messages/JavaCompilerBundle.properties index e0d4c4c7e35f..3659dd89ade5 100644 --- a/java/compiler/openapi/resources/messages/JavaCompilerBundle.properties +++ b/java/compiler/openapi/resources/messages/JavaCompilerBundle.properties @@ -220,6 +220,7 @@ unknown.build.process.error=unknown error intention.name.make.implements=Make implements ''{0}'' intention.name.make.extends=Make extends ''{0}'' classes.up.to.date.check=Classes up-to-Date Check +refresh.compiler.ref.index=Refresh Compiler Reference Index action.run.all.affected.tests.text=Run All Affected Tests popup.title.affected.tests.counts=Found {0} {1, choice, 0#Test|1#Tests} in {2} {3, choice, 0#Class|1#Classes} for {4} diff --git a/java/compiler/openapi/src/com/intellij/compiler/ModuleCompilerUtil.java b/java/compiler/openapi/src/com/intellij/compiler/ModuleCompilerUtil.java index 88525bd9ddf6..b04573f417ab 100644 --- a/java/compiler/openapi/src/com/intellij/compiler/ModuleCompilerUtil.java +++ b/java/compiler/openapi/src/com/intellij/compiler/ModuleCompilerUtil.java @@ -1,10 +1,7 @@ -// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.compiler; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; import com.intellij.openapi.roots.ui.configuration.DefaultModulesProvider; @@ -18,73 +15,14 @@ import org.jetbrains.jps.model.java.JavaSourceRootType; import java.util.*; -/** - * @author dsl - */ public final class ModuleCompilerUtil { - private static final Logger LOG = Logger.getInstance(ModuleCompilerUtil.class); private ModuleCompilerUtil() { } public static Module @NotNull [] getDependencies(Module module) { return ModuleRootManager.getInstance(module).getDependencies(); } - @NotNull - private static Graph createModuleGraph(Module @NotNull [] modules) { - return GraphGenerator.generate(CachingSemiGraph.cache(new InboundSemiGraph<>() { - @NotNull - @Override - public Collection getNodes() { - return Arrays.asList(modules); - } - - @NotNull - @Override - public Iterator getIn(Module module) { - return Arrays.asList(getDependencies(module)).iterator(); - } - })); - } - - @NotNull - public static List> getSortedModuleChunks(@NotNull Project project, @NotNull List modules) { - final Module[] allModules = ModuleManager.getInstance(project).getModules(); - final List> chunks = getSortedChunks(createModuleGraph(allModules)); - - final Set modulesSet = new HashSet<>(modules); - // leave only those chunks that contain at least one module from modules - chunks.removeIf(chunk -> !ContainerUtil.intersects(chunk.getNodes(), modulesSet)); - return chunks; - } - - @NotNull - private static List> getSortedChunks(@NotNull Graph graph) { - final Graph> chunkGraph = toChunkGraph(graph); - final List> chunks = new ArrayList<>(chunkGraph.getNodes()); - DFSTBuilder> builder = new DFSTBuilder<>(chunkGraph); - if (!builder.isAcyclic()) { - LOG.error("Acyclic graph expected"); - return null; - } - - chunks.sort(builder.comparator()); - return chunks; - } - - @NotNull - public static Graph> toChunkGraph(@NotNull Graph graph) { - return GraphAlgorithms.getInstance().computeSCCGraph(graph); - } - - public static void sortModules(final Project project, final List modules) { - ApplicationManager.getApplication().runReadAction(() -> { - Comparator comparator = ModuleManager.getInstance(project).moduleDependencyComparator(); - modules.sort(comparator); - }); - } - - @NotNull - public static List> getCyclicDependencies(@NotNull Project project, @NotNull List modules) { + public static @NotNull List> getCyclicDependencies(@NotNull Project project, @NotNull List modules) { Collection> chunks = computeSourceSetCycles(new DefaultModulesProvider(project)); final Set modulesSet = new HashSet<>(modules); return ContainerUtil.filter(chunks, chunk -> { @@ -97,12 +35,10 @@ public final class ModuleCompilerUtil { }); } - @NotNull - private static Graph createModuleSourceDependenciesGraph(@NotNull RootModelProvider provider) { + private static @NotNull Graph createModuleSourceDependenciesGraph(@NotNull RootModelProvider provider) { return GraphGenerator.generate(CachingSemiGraph.cache(new InboundSemiGraph<>() { - @NotNull @Override - public Collection getNodes() { + public @NotNull Collection getNodes() { Module[] modules = provider.getModules(); List result = new ArrayList<>(modules.length * 2); for (Module module : modules) { @@ -112,9 +48,8 @@ public final class ModuleCompilerUtil { return result; } - @NotNull @Override - public Iterator getIn(final ModuleSourceSet n) { + public @NotNull Iterator getIn(final ModuleSourceSet n) { ModuleRootModel model = provider.getRootModel(n.getModule()); OrderEnumerator enumerator = model.orderEntries().compileOnly(); if (n.getType() == ModuleSourceSet.Type.PRODUCTION) { @@ -133,8 +68,7 @@ public final class ModuleCompilerUtil { })); } - @NotNull - public static List> computeSourceSetCycles(@NotNull ModulesProvider provider) { + public static @NotNull List> computeSourceSetCycles(@NotNull ModulesProvider provider) { Graph graph = createModuleSourceDependenciesGraph(provider); Collection> chunks = GraphAlgorithms.getInstance().computeStronglyConnectedComponents(graph); return removeSingleElementChunks(removeDummyNodes(filterDuplicates(removeSingleElementChunks(chunks)), provider)); @@ -172,8 +106,7 @@ public final class ModuleCompilerUtil { /** * Remove cycles in tests included in cycles between production parts */ - @NotNull - private static List> filterDuplicates(@NotNull Collection> sourceSetCycles) { + private static @NotNull List> filterDuplicates(@NotNull Collection> sourceSetCycles) { final List> productionCycles = new ArrayList<>(); for (Chunk cycle : sourceSetCycles) { @@ -192,8 +125,7 @@ public final class ModuleCompilerUtil { }); } - @Nullable - private static ModuleSourceSet.Type getCommonType(@NotNull Chunk cycle) { + private static @Nullable ModuleSourceSet.Type getCommonType(@NotNull Chunk cycle) { ModuleSourceSet.Type type = null; for (ModuleSourceSet set : cycle.getNodes()) { if (type == null) { diff --git a/java/compiler/openapi/src/com/intellij/openapi/compiler/CompileStatusNotification.kt b/java/compiler/openapi/src/com/intellij/openapi/compiler/CompileStatusNotification.kt index b88aef9f267b..566dee2fabfe 100644 --- a/java/compiler/openapi/src/com/intellij/openapi/compiler/CompileStatusNotification.kt +++ b/java/compiler/openapi/src/com/intellij/openapi/compiler/CompileStatusNotification.kt @@ -1,29 +1,13 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.openapi.compiler; - -import org.jetbrains.annotations.NotNull; +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.openapi.compiler /** * A callback interface passed to ComplerManager methods. Provides notification similar to - * {@link CompilationStatusListener}. + * [CompilationStatusListener]. * - * @see CompilerManager#compile(CompileScope, CompileStatusNotification) + * @see CompilerManager.compile */ -public interface CompileStatusNotification { +interface CompileStatusNotification { /** * Invoked in a Swing dispatch thread after the compilation is finished. * @@ -32,5 +16,5 @@ public interface CompileStatusNotification { * @param warnings warning count * @param compileContext context for the finished compilation */ - void finished(boolean aborted, int errors, int warnings, @NotNull CompileContext compileContext); -} + fun finished(aborted: Boolean, errors: Int, warnings: Int, compileContext: CompileContext) +} \ No newline at end of file diff --git a/java/compiler/openapi/src/com/intellij/openapi/compiler/CompilerManager.java b/java/compiler/openapi/src/com/intellij/openapi/compiler/CompilerManager.java index 6f239def5abc..a241700e4da1 100644 --- a/java/compiler/openapi/src/com/intellij/openapi/compiler/CompilerManager.java +++ b/java/compiler/openapi/src/com/intellij/openapi/compiler/CompilerManager.java @@ -17,7 +17,6 @@ import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.List; -import java.util.concurrent.CompletableFuture; /** * A "root" class in compiler subsystem - allows one to register a custom compiler or a compilation task, register/unregister a compilation listener @@ -196,13 +195,6 @@ public abstract class CompilerManager { @Deprecated public abstract boolean isUpToDate(@NotNull CompileScope scope); - /** - * Checks if compile scope given is up-to-date - * @param scope - * Returns true if make on the scope specified wouldn't do anything or false if something is to be compiled or deleted - */ - public abstract CompletableFuture isUpToDateAsync(@NotNull CompileScope scope); - /** * Rebuild the whole project from scratch. Compiler excludes are honored. * diff --git a/java/compiler/openapi/src/com/intellij/openapi/compiler/CompilerPaths.java b/java/compiler/openapi/src/com/intellij/openapi/compiler/CompilerPaths.java index 5ef70446627a..9b9f45b11ec7 100644 --- a/java/compiler/openapi/src/com/intellij/openapi/compiler/CompilerPaths.java +++ b/java/compiler/openapi/src/com/intellij/openapi/compiler/CompilerPaths.java @@ -1,4 +1,4 @@ -// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.compiler; import com.intellij.compiler.CompilerConfiguration; @@ -51,8 +51,7 @@ public class CompilerPaths { /** * @return a directory under IDEA "system" directory where all files related to compiler subsystem are stored (such as compiler caches or generated files) */ - @NotNull - public static File getCompilerSystemDirectory(@NotNull Project project) { + public static @NotNull File getCompilerSystemDirectory(@NotNull Project project) { return ProjectUtil.getProjectCachePath(project, "compiler").toFile(); } @@ -61,8 +60,7 @@ public class CompilerPaths { * @return a directory to which the sources (or test sources depending on the second parameter) should be compiled. * Null is returned if output directory is not specified or is not valid */ - @Nullable - public static VirtualFile getModuleOutputDirectory(@NotNull Module module, boolean forTestClasses) { + public static @Nullable VirtualFile getModuleOutputDirectory(@NotNull Module module, boolean forTestClasses) { final CompilerModuleExtension compilerModuleExtension = CompilerModuleExtension.getInstance(module); if (compilerModuleExtension == null) { return null; @@ -94,8 +92,7 @@ public class CompilerPaths { * The same as {@link #getModuleOutputDirectory} but returns String. * The method still returns a non-null value if the output path is specified in Settings but does not exist on disk. */ - @Nullable - public static String getModuleOutputPath(final Module module, boolean forTestClasses) { + public static @Nullable String getModuleOutputPath(Module module, boolean forTestClasses) { final CompilerModuleExtension extension = CompilerModuleExtension.getInstance(module); if (extension == null) { return null; @@ -125,8 +122,7 @@ public class CompilerPaths { return outPathUrl != null? VirtualFileManager.extractPath(outPathUrl) : null; } - @Nullable - public static String getAnnotationProcessorsGenerationPath(Module module, boolean forTests) { + public static @Nullable String getAnnotationProcessorsGenerationPath(Module module, boolean forTests) { final AnnotationProcessingConfiguration config = CompilerConfiguration.getInstance(module.getProject()).getAnnotationProcessingConfiguration(module); final String sourceDirName = config.getGeneratedSourcesDirectoryName(forTests); if (config.isOutputRelativeToContentRoot()) { diff --git a/platform/core-api/src/com/intellij/openapi/application/coroutines.kt b/platform/core-api/src/com/intellij/openapi/application/coroutines.kt index e2d8a5c8ffdb..94a749762f79 100644 --- a/platform/core-api/src/com/intellij/openapi/application/coroutines.kt +++ b/platform/core-api/src/com/intellij/openapi/application/coroutines.kt @@ -2,7 +2,8 @@ package com.intellij.openapi.application import com.intellij.openapi.project.Project -import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.* +import org.jetbrains.annotations.ApiStatus import kotlin.coroutines.CoroutineContext /** @@ -106,3 +107,14 @@ fun ModalityState.asContextElement(): CoroutineContext = coroutineSupport().asCo val Dispatchers.EDT: CoroutineContext get() = coroutineSupport().edtDispatcher() private fun coroutineSupport() = ApplicationManager.getApplication().getService(CoroutineSupport::class.java) + +@ApiStatus.Internal +@ApiStatus.Experimental +fun createSupervisorCoroutineScope(parentScope: CoroutineScope, dispatcher: CoroutineDispatcher? = null): CoroutineScope { + val parentContext = parentScope.coroutineContext + var context = parentContext + SupervisorJob(parent = parentContext.job) + if (dispatcher != null) { + context += dispatcher + } + return CoroutineScope(context) +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/build/BuildTreeConsoleView.java b/platform/lang-impl/src/com/intellij/build/BuildTreeConsoleView.java index d20ff3d5a2a3..1733cf2e9a7c 100644 --- a/platform/lang-impl/src/com/intellij/build/BuildTreeConsoleView.java +++ b/platform/lang-impl/src/com/intellij/build/BuildTreeConsoleView.java @@ -1,4 +1,4 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.build; import com.intellij.build.events.*; @@ -97,7 +97,7 @@ import static com.intellij.util.ui.UIUtil.*; /** * @author Vladislav.Soroka */ -public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildConsoleView, Filterable, OccurenceNavigator { +public final class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildConsoleView, Filterable, OccurenceNavigator { private static final Logger LOG = Logger.getInstance(BuildTreeConsoleView.class); @NonNls private static final String TREE = "tree"; @@ -122,10 +122,20 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon private final ProblemOccurrenceNavigatorSupport myOccurrenceNavigatorSupport; private final Set myDeferredEvents = ContainerUtil.newConcurrentSet(); + /** + * @deprecated BuildViewSettingsProvider is not used anymore. + */ + @Deprecated public BuildTreeConsoleView(@NotNull Project project, @NotNull BuildDescriptor buildDescriptor, @Nullable ExecutionConsole executionConsole, @NotNull BuildViewSettingsProvider buildViewSettingsProvider) { + this(project, buildDescriptor, executionConsole); + } + + public BuildTreeConsoleView(@NotNull Project project, + @NotNull BuildDescriptor buildDescriptor, + @Nullable ExecutionConsole executionConsole) { myProject = project; myBuildDescriptor = buildDescriptor instanceof DefaultBuildDescriptor ? (DefaultBuildDescriptor)buildDescriptor @@ -159,7 +169,7 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon myThreeComponentsSplitter.setFirstComponent(myContentPanel); List filters = myBuildDescriptor.getExecutionFilters(); myConsoleViewHandler = new ConsoleViewHandler(myProject, myTree, myBuildProgressRootNode, this, - executionConsole, filters, buildViewSettingsProvider); + executionConsole, filters); myThreeComponentsSplitter.setSecondComponent(myConsoleViewHandler.getComponent()); myPanel.add(myThreeComponentsSplitter, BorderLayout.CENTER); BuildTreeFilters.install(this); @@ -253,7 +263,7 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon return executionNode -> executionNode == getBuildProgressRootNode() || executionNode.isRunning() || executionNode.isFailed() || - myNodeFilters.stream().anyMatch(predicate -> predicate.test(executionNode)); + ContainerUtil.exists(myNodeFilters, predicate -> predicate.test(executionNode)); } @Override @@ -357,7 +367,7 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon if (parentNode != null) { if (parentNode != buildProgressRootNode) { myConsoleViewHandler.addOutput(parentNode, buildId, event); - myConsoleViewHandler.addOutput(parentNode, "\n", true); + myConsoleViewHandler.addOutput(parentNode); } reportMessageKind(messageEvent.getKind(), parentNode, structureChanged); } @@ -904,14 +914,13 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon return myTreeModel.getInvoker().invokeLater(task); } - private static class ConsoleViewHandler implements Disposable { + private static final class ConsoleViewHandler implements Disposable { private static final String EMPTY_CONSOLE_NAME = "empty"; private final Project myProject; private final JPanel myPanel; private final CompositeView myView; private final AtomicReference myNodeConsoleViewName = new AtomicReference<>(); private final Map>> deferredNodeOutput = new ConcurrentHashMap<>(); - private final @NotNull BuildViewSettingsProvider myViewSettingsProvider; private @Nullable ExecutionNode myExecutionNode; private @NotNull final List myExecutionConsoleFilters; private final BuildProgressStripe myPanelWithProgress; @@ -923,12 +932,10 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon @NotNull ExecutionNode buildProgressRootNode, @NotNull Disposable parentDisposable, @Nullable ExecutionConsole executionConsole, - @NotNull List executionConsoleFilters, - @NotNull BuildViewSettingsProvider buildViewSettingsProvider) { + @NotNull List executionConsoleFilters) { myProject = project; myPanel = new NonOpaquePanel(new BorderLayout()); myPanelWithProgress = new BuildProgressStripe(myPanel, parentDisposable, ProgressIndicatorWithDelayedPresentation.DEFAULT_PROGRESS_DIALOG_POSTPONE_TIME_MILLIS); - myViewSettingsProvider = buildViewSettingsProvider; myExecutionConsoleFilters = executionConsoleFilters; Disposer.register(parentDisposable, this); myView = new CompositeView<>(null) { @@ -1073,8 +1080,8 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon }); } - private void addOutput(@NotNull ExecutionNode node, @NotNull String text, boolean stdOut) { - addOutput(node, view -> view.append(text, stdOut)); + private void addOutput(@NotNull ExecutionNode node) { + addOutput(node, view -> view.append("\n", true)); } private void addOutput(@NotNull ExecutionNode node, @NotNull Object buildId, BuildEvent event) { @@ -1296,8 +1303,8 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon } @Override - public @NotNull Object[] getChildElements(@NotNull Object element) { - // This .toArray() is still slow but it is called less frequently because of batching in AsyncTreeModel and process less data if + public Object @NotNull [] getChildElements(@NotNull Object element) { + // This .toArray() is still slow, but it is called less frequently because of batching in AsyncTreeModel and process less data if // filters are applied. return ((ExecutionNode)element).getChildList().toArray(); } diff --git a/platform/lang-impl/src/com/intellij/build/BuildView.java b/platform/lang-impl/src/com/intellij/build/BuildView.java index 94f49bf4797a..9c0def1aa625 100644 --- a/platform/lang-impl/src/com/intellij/build/BuildView.java +++ b/platform/lang-impl/src/com/intellij/build/BuildView.java @@ -1,4 +1,4 @@ -// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.build; import com.intellij.build.events.BuildEvent; @@ -23,7 +23,6 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.util.Consumer; -import com.intellij.util.concurrency.EdtExecutorService; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NonNls; @@ -106,14 +105,16 @@ public class BuildView extends CompositeView else { BuildTreeConsoleView eventView = getEventView(); if (eventView != null) { - EdtExecutorService.getInstance().execute(() -> eventView.onEvent(buildId, event)); + eventView.onEvent(buildId, event); } } } private void onStartBuild(@NotNull Object buildId, @NotNull StartBuildEvent startBuildEvent) { Application application = ApplicationManager.getApplication(); - if (application.isHeadlessEnvironment() && !application.isUnitTestMode()) return; + if (application.isHeadlessEnvironment() && !application.isUnitTestMode()) { + return; + } if (startBuildEvent instanceof StartBuildEventImpl) { myViewSettingsProvider = ((StartBuildEventImpl)startBuildEvent).getBuildViewSettingsProvider(); @@ -146,7 +147,7 @@ public class BuildView extends CompositeView eventView = getEventView(); if (eventView == null) { String eventViewName = BuildTreeConsoleView.class.getName(); - eventView = new BuildTreeConsoleView(myProject, myBuildDescriptor, myExecutionConsole, myViewSettingsProvider); + eventView = new BuildTreeConsoleView(myProject, myBuildDescriptor, myExecutionConsole); addView(eventView, eventViewName); showView(eventViewName); } @@ -177,9 +178,8 @@ public class BuildView extends CompositeView } } - @Nullable @ApiStatus.Internal - public ExecutionConsole getConsoleView() { + public @Nullable ExecutionConsole getConsoleView() { return myExecutionConsole; } @@ -209,8 +209,7 @@ public class BuildView extends CompositeView } } - @Nullable - private R getConsoleViewValue(Function viewConsumer) { + private @Nullable R getConsoleViewValue(Function viewConsumer) { ExecutionConsole console = getConsoleView(); if (console instanceof ConsoleView) { return viewConsumer.apply((ConsoleView)console); @@ -333,9 +332,8 @@ public class BuildView extends CompositeView delegateToConsoleView(ConsoleView::allowHeavyFilters); } - @Nullable @Override - public Object getData(@NotNull String dataId) { + public @Nullable Object getData(@NotNull String dataId) { if (LangDataKeys.CONSOLE_VIEW.is(dataId)) { return getConsoleView(); } @@ -359,9 +357,8 @@ public class BuildView extends CompositeView return getEventView() != null; } - @NotNull @Override - public Predicate getFilter() { + public @NotNull Predicate getFilter() { BuildTreeConsoleView eventView = getEventView(); return eventView == null ? executionNode -> true : eventView.getFilter(); } @@ -388,8 +385,7 @@ public class BuildView extends CompositeView return eventView != null && eventView.contains(filter); } - @NotNull - private OccurenceNavigator getOccurenceNavigator() { + private @NotNull OccurenceNavigator getOccurenceNavigator() { BuildTreeConsoleView eventView = getEventView(); if (eventView != null) return eventView; ExecutionConsole executionConsole = getConsoleView(); @@ -419,15 +415,13 @@ public class BuildView extends CompositeView return getOccurenceNavigator().goPreviousOccurence(); } - @NotNull @Override - public String getNextOccurenceActionName() { + public @NotNull String getNextOccurenceActionName() { return getOccurenceNavigator().getNextOccurenceActionName(); } - @NotNull @Override - public String getPreviousOccurenceActionName() { + public @NotNull String getPreviousOccurenceActionName() { return getOccurenceNavigator().getPreviousOccurenceActionName(); } } diff --git a/platform/lang-impl/testSources/com/intellij/build/BuildTreeConsoleViewTest.kt b/platform/lang-impl/testSources/com/intellij/build/BuildTreeConsoleViewTest.kt index c71ded353c70..fc572a07144a 100644 --- a/platform/lang-impl/testSources/com/intellij/build/BuildTreeConsoleViewTest.kt +++ b/platform/lang-impl/testSources/com/intellij/build/BuildTreeConsoleViewTest.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.build import com.intellij.build.events.MessageEvent @@ -32,7 +32,7 @@ class BuildTreeConsoleViewTest : LightPlatformTestCase() { "test descriptor", "fake path", 1L) - treeConsoleView = BuildTreeConsoleView(project, buildDescriptor, null) { false } + treeConsoleView = BuildTreeConsoleView(project, buildDescriptor, null) } @Test diff --git a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowFactory.java b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowFactory.java index 12d8d5d5177b..aecf01eb481c 100644 --- a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowFactory.java +++ b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowFactory.java @@ -41,7 +41,7 @@ public interface ToolWindowFactory { /** * @deprecated Use {@link ToolWindowEP#isDoNotActivateOnStart} */ - @Deprecated + @Deprecated(forRemoval = true) default boolean isDoNotActivateOnStart() { return false; } diff --git a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowManager.kt b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowManager.kt index aaadcefe8f10..2f5c7d8e94af 100644 --- a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowManager.kt +++ b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowManager.kt @@ -192,8 +192,16 @@ class RegisterToolWindowTaskBuilder @PublishedApi internal constructor(private v @PublishedApi internal fun build(): RegisterToolWindowTask { - val result = RegisterToolWindowTask(id, anchor, null, sideTool, canCloseContent, true, shouldBeAvailable, contentFactory, icon, - stripeTitle) + val result = RegisterToolWindowTask(id = id, + anchor = anchor, + component = null, + sideTool = sideTool, + canCloseContent = canCloseContent, + canWorkInDumbMode = true, + shouldBeAvailable = shouldBeAvailable, + contentFactory = contentFactory, + icon = icon, + stripeTitle = stripeTitle) result.hideOnEmptyContent = hideOnEmptyContent return result diff --git a/platform/platform-api/src/com/intellij/util/ui/tree/TreeUtil.java b/platform/platform-api/src/com/intellij/util/ui/tree/TreeUtil.java index c1bcd445f363..f235bc7033cb 100644 --- a/platform/platform-api/src/com/intellij/util/ui/tree/TreeUtil.java +++ b/platform/platform-api/src/com/intellij/util/ui/tree/TreeUtil.java @@ -1,4 +1,4 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.util.ui.tree; import com.intellij.ide.ui.UISettings; @@ -85,15 +85,13 @@ public final class TreeUtil { tree.putClientProperty(NAVIGATABLE_PROVIDER, provider); } - @NotNull - public static JBTreeTraverser treeTraverser(@NotNull JTree tree) { + public static @NotNull JBTreeTraverser treeTraverser(@NotNull JTree tree) { TreeModel model = tree.getModel(); Object root = model.getRoot(); return JBTreeTraverser.from(node -> nodeChildren(node, model)).withRoot(root); } - @NotNull - public static JBTreeTraverser treePathTraverser(@NotNull JTree tree) { + public static @NotNull JBTreeTraverser treePathTraverser(@NotNull JTree tree) { TreeModel model = tree.getModel(); Object root = model.getRoot(); TreePath rootPath = root == null ? null : new TreePath(root); @@ -102,19 +100,16 @@ public final class TreeUtil { .withRoot(rootPath); } - @NotNull - public static JBIterable nodeChildren(@Nullable Object node, @NotNull TreeModel model) { + public static @NotNull JBIterable nodeChildren(@Nullable Object node, @NotNull TreeModel model) { int count = model.getChildCount(node); return count == 0 ? JBIterable.empty() : NUMBERS.take(count).map(index -> model.getChild(node, index)); } - @NotNull - public static JBTreeTraverser treeNodeTraverser(@Nullable TreeNode treeNode) { + public static @NotNull JBTreeTraverser treeNodeTraverser(@Nullable TreeNode treeNode) { return JBTreeTraverser.from(node -> nodeChildren(node)).withRoot(treeNode); } - @NotNull - public static JBIterable nodeChildren(@Nullable TreeNode treeNode) { + public static @NotNull JBIterable nodeChildren(@Nullable TreeNode treeNode) { int count = treeNode == null ? 0 : treeNode.getChildCount(); return count == 0 ? JBIterable.empty() : NUMBERS.take(count).map(index -> treeNode.getChildAt(index)); } @@ -169,8 +164,7 @@ public final class TreeUtil { * @param tree a tree, which viewable paths are processed * @return a list of expanded paths */ - @NotNull - public static List collectExpandedPaths(@NotNull JTree tree) { + public static @NotNull List collectExpandedPaths(@NotNull JTree tree) { return collectExpandedObjects(tree, Function.identity()); } @@ -178,8 +172,7 @@ public final class TreeUtil { * @param tree a tree, which viewable paths are processed * @return a list of user objects which correspond to expanded paths under the specified root node */ - @NotNull - public static List collectExpandedUserObjects(@NotNull JTree tree) { + public static @NotNull List collectExpandedUserObjects(@NotNull JTree tree) { return collectExpandedObjects(tree, TreeUtil::getLastUserObject); } @@ -188,8 +181,7 @@ public final class TreeUtil { * @param mapper a function to convert an expanded tree path to a corresponding object * @return a list of objects which correspond to expanded paths under the specified root node */ - @NotNull - public static List collectExpandedObjects(@NotNull JTree tree, @NotNull Function mapper) { + public static @NotNull List collectExpandedObjects(@NotNull JTree tree, @NotNull Function mapper) { int count = tree.getRowCount(); if (count == 0) return Collections.emptyList(); // tree is empty List list = new ArrayList<>(); @@ -202,8 +194,7 @@ public final class TreeUtil { return list; } - @Nullable - public static T findObjectInPath(@Nullable TreePath path, @NotNull Class clazz) { + public static @Nullable T findObjectInPath(@Nullable TreePath path, @NotNull Class clazz) { while (path != null) { T object = getLastUserObject(clazz, path); if (object != null) return object; @@ -217,8 +208,7 @@ public final class TreeUtil { * @param type a {@code Class} object to filter selected user objects * @return a list of user objects of the specified type retrieved from all selected paths */ - @NotNull - public static List collectSelectedObjectsOfType(@NotNull JTree tree, @NotNull Class type) { + public static @NotNull List collectSelectedObjectsOfType(@NotNull JTree tree, @NotNull Class type) { return collectSelectedObjects(tree, path -> getLastUserObject(type, path)); } @@ -227,8 +217,7 @@ public final class TreeUtil { * @param root an ascendant tree path to filter expanded tree paths * @return a list of expanded paths under the specified root node */ - @NotNull - public static List collectExpandedPaths(@NotNull JTree tree, @NotNull TreePath root) { + public static @NotNull List collectExpandedPaths(@NotNull JTree tree, @NotNull TreePath root) { return collectExpandedObjects(tree, root, Function.identity()); } @@ -237,8 +226,7 @@ public final class TreeUtil { * @param root an ascendant tree path to filter expanded tree paths * @return a list of user objects which correspond to expanded paths under the specified root node */ - @NotNull - public static List collectExpandedUserObjects(@NotNull JTree tree, @NotNull TreePath root) { + public static @NotNull List collectExpandedUserObjects(@NotNull JTree tree, @NotNull TreePath root) { return collectExpandedObjects(tree, root, TreeUtil::getLastUserObject); } @@ -248,8 +236,7 @@ public final class TreeUtil { * @param mapper a function to convert an expanded tree path to a corresponding object * @return a list of objects which correspond to expanded paths under the specified root node */ - @NotNull - public static List collectExpandedObjects(@NotNull JTree tree, @NotNull TreePath root, @NotNull Function mapper) { + public static @NotNull List collectExpandedObjects(@NotNull JTree tree, @NotNull TreePath root, @NotNull Function mapper) { int count = tree.getRowCount(); if (count == 0) return Collections.emptyList(); // tree is empty int row = tree.getRowForPath(root); @@ -275,14 +262,13 @@ public final class TreeUtil { * @param tree JTree to apply expansion status to * @param paths to expand. See {@link #collectExpandedPaths(JTree, TreePath)} */ - public static void restoreExpandedPaths(@NotNull final JTree tree, @NotNull final List paths){ + public static void restoreExpandedPaths(final @NotNull JTree tree, final @NotNull List paths){ for(int i = paths.size() - 1; i >= 0; i--){ tree.expandPath(paths.get(i)); } } - @NotNull - public static TreePath getPath(@NotNull TreeNode aRootNode, @NotNull TreeNode aNode) { + public static @NotNull TreePath getPath(@NotNull TreeNode aRootNode, @NotNull TreeNode aNode) { TreeNode[] nodes = getPathFromRootTo(aRootNode, aNode, true); return new TreePath(nodes); } @@ -296,8 +282,7 @@ public final class TreeUtil { return false; } - @NotNull - public static TreePath getPathFromRoot(@NotNull TreeNode node) { + public static @NotNull TreePath getPathFromRoot(@NotNull TreeNode node) { TreeNode[] path = getPathFromRootTo(null, node, false); return new TreePath(path); } @@ -315,8 +300,7 @@ public final class TreeUtil { return path; } - @Nullable - public static TreeNode findNodeWithObject(final Object object, @NotNull final TreeModel model, final Object parent) { + public static @Nullable TreeNode findNodeWithObject(final Object object, final @NotNull TreeModel model, final Object parent) { for (int i = 0; i < model.getChildCount(parent); i++) { final DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) model.getChild(parent, i); if (childNode.getUserObject().equals(object)) return childNode; @@ -329,7 +313,7 @@ public final class TreeUtil { * * @param tree to remove selected node from. */ - public static void removeSelected(@NotNull final JTree tree) { + public static void removeSelected(final @NotNull JTree tree) { TreePath[] paths = tree.getSelectionPaths(); if (paths == null) { return; @@ -339,18 +323,16 @@ public final class TreeUtil { } } - public static void removeLastPathComponent(@NotNull final JTree tree, @NotNull final TreePath pathToBeRemoved){ + public static void removeLastPathComponent(final @NotNull JTree tree, final @NotNull TreePath pathToBeRemoved){ removeLastPathComponent((DefaultTreeModel)tree.getModel(), pathToBeRemoved).restoreSelection(tree); } - @Nullable - public static DefaultMutableTreeNode findNodeWithObject(@NotNull final DefaultMutableTreeNode aRoot, final Object aObject) { + public static @Nullable DefaultMutableTreeNode findNodeWithObject(final @NotNull DefaultMutableTreeNode aRoot, final Object aObject) { return findNode(aRoot, node -> Comparing.equal(node.getUserObject(), aObject)); } - @Nullable - public static DefaultMutableTreeNode findNode(@NotNull final DefaultMutableTreeNode aRoot, - @NotNull final Condition condition) { + public static @Nullable DefaultMutableTreeNode findNode(final @NotNull DefaultMutableTreeNode aRoot, + final @NotNull Condition condition) { if (condition.value(aRoot)) { return aRoot; } else { @@ -371,13 +353,11 @@ public final class TreeUtil { * @return a callback that will be done when first visible node is selected * @see #promiseSelectFirst */ - @NotNull - public static ActionCallback selectFirstNode(@NotNull JTree tree) { + public static @NotNull ActionCallback selectFirstNode(@NotNull JTree tree) { return Promises.toActionCallback(promiseSelectFirst(tree)); } - @NotNull - public static TreePath getFirstNodePath(@NotNull JTree tree) { + public static @NotNull TreePath getFirstNodePath(@NotNull JTree tree) { TreeModel model = tree.getModel(); Object root = model.getRoot(); TreePath selectionPath = new TreePath(root); @@ -396,8 +376,7 @@ public final class TreeUtil { * @deprecated use {@link #promiseSelectFirstLeaf} */ @Deprecated(forRemoval = true) - @NotNull - public static TreePath getFirstLeafNodePath(@NotNull JTree tree) { + public static @NotNull TreePath getFirstLeafNodePath(@NotNull JTree tree) { final TreeModel model = tree.getModel(); Object root = model.getRoot(); TreePath selectionPath = new TreePath(root); @@ -409,8 +388,7 @@ public final class TreeUtil { return selectionPath; } - @NotNull - private static IndexTreePathState removeLastPathComponent(@NotNull final DefaultTreeModel model, @NotNull final TreePath pathToBeRemoved) { + private static @NotNull IndexTreePathState removeLastPathComponent(final @NotNull DefaultTreeModel model, final @NotNull TreePath pathToBeRemoved) { final IndexTreePathState selectionState = new IndexTreePathState(pathToBeRemoved); if (((MutableTreeNode) pathToBeRemoved.getLastPathComponent()).getParent() == null) return selectionState; model.removeNodeFromParent((MutableTreeNode)pathToBeRemoved.getLastPathComponent()); @@ -418,11 +396,11 @@ public final class TreeUtil { } - public static void sort(@NotNull final DefaultTreeModel model, @Nullable Comparator comparator) { + public static void sort(final @NotNull DefaultTreeModel model, @Nullable Comparator comparator) { sort((DefaultMutableTreeNode) model.getRoot(), comparator); } - public static void sort(@NotNull final DefaultMutableTreeNode node, @Nullable Comparator comparator) { + public static void sort(final @NotNull DefaultMutableTreeNode node, @Nullable Comparator comparator) { sortRecursively(node, comparator); } @@ -444,7 +422,7 @@ public final class TreeUtil { addChildrenTo(node, children); } - public static void addChildrenTo(@NotNull final MutableTreeNode node, @NotNull final List children) { + public static void addChildrenTo(final @NotNull MutableTreeNode node, final @NotNull List children) { for (final Object aChildren : children) { final MutableTreeNode child = (MutableTreeNode)aChildren; node.insert(child, node.getChildCount()); @@ -505,13 +483,11 @@ public final class TreeUtil { internalSelect(tree, paths); } - @NotNull - public static ActionCallback selectPath(@NotNull final JTree tree, final TreePath path) { + public static @NotNull ActionCallback selectPath(final @NotNull JTree tree, final TreePath path) { return selectPath(tree, path, true); } - @NotNull - public static ActionCallback selectPath(@NotNull final JTree tree, final TreePath path, boolean center) { + public static @NotNull ActionCallback selectPath(final @NotNull JTree tree, final TreePath path, boolean center) { tree.makeVisible(path); Rectangle bounds = tree.getPathBounds(path); if (bounds == null) return ActionCallback.REJECTED; @@ -529,8 +505,7 @@ public final class TreeUtil { } } - @NotNull - public static ActionCallback moveDown(@NotNull final JTree tree) { + public static @NotNull ActionCallback moveDown(final @NotNull JTree tree) { final int size = tree.getRowCount(); int row = tree.getLeadSelectionRow(); if (row < size - 1) { @@ -541,8 +516,7 @@ public final class TreeUtil { } } - @NotNull - public static ActionCallback moveUp(@NotNull final JTree tree) { + public static @NotNull ActionCallback moveUp(final @NotNull JTree tree) { int row = tree.getLeadSelectionRow(); if (row > 0) { row--; @@ -552,8 +526,7 @@ public final class TreeUtil { } } - @NotNull - public static ActionCallback movePageUp(@NotNull final JTree tree) { + public static @NotNull ActionCallback movePageUp(final @NotNull JTree tree) { final int visible = getVisibleRowCount(tree); if (visible <= 0){ return moveHome(tree); @@ -565,8 +538,7 @@ public final class TreeUtil { return showAndSelect(tree, top, bottom, row, getSelectedRow(tree)); } - @NotNull - public static ActionCallback movePageDown(@NotNull final JTree tree) { + public static @NotNull ActionCallback movePageDown(final @NotNull JTree tree) { final int visible = getVisibleRowCount(tree); if (visible <= 0){ return moveEnd(tree); @@ -579,28 +551,23 @@ public final class TreeUtil { return showAndSelect(tree, top, bottom, index, getSelectedRow(tree)); } - @NotNull - private static ActionCallback moveHome(@NotNull final JTree tree) { + private static @NotNull ActionCallback moveHome(final @NotNull JTree tree) { return showRowCentred(tree, 0); } - @NotNull - private static ActionCallback moveEnd(@NotNull final JTree tree) { + private static @NotNull ActionCallback moveEnd(final @NotNull JTree tree) { return showRowCentred(tree, tree.getRowCount() - 1); } - @NotNull - private static ActionCallback showRowCentred(@NotNull final JTree tree, final int row) { + private static @NotNull ActionCallback showRowCentred(final @NotNull JTree tree, final int row) { return showRowCentered(tree, row, true); } - @NotNull - public static ActionCallback showRowCentered(@NotNull final JTree tree, final int row, final boolean centerHorizontally) { + public static @NotNull ActionCallback showRowCentered(final @NotNull JTree tree, final int row, final boolean centerHorizontally) { return showRowCentered(tree, row, centerHorizontally, true); } - @NotNull - public static ActionCallback showRowCentered(@NotNull final JTree tree, final int row, final boolean centerHorizontally, boolean scroll) { + public static @NotNull ActionCallback showRowCentered(final @NotNull JTree tree, final int row, final boolean centerHorizontally, boolean scroll) { final int visible = getVisibleRowCount(tree); final int top = visible > 0 ? row - (visible - 1)/ 2 : row; @@ -608,23 +575,19 @@ public final class TreeUtil { return showAndSelect(tree, top, bottom, row, -1, false, scroll, false); } - @NotNull - public static ActionCallback showAndSelect(@NotNull final JTree tree, int top, int bottom, final int row, final int previous) { + public static @NotNull ActionCallback showAndSelect(final @NotNull JTree tree, int top, int bottom, final int row, final int previous) { return showAndSelect(tree, top, bottom, row, previous, false); } - @NotNull - public static ActionCallback showAndSelect(@NotNull final JTree tree, int top, int bottom, final int row, final int previous, boolean addToSelection) { + public static @NotNull ActionCallback showAndSelect(final @NotNull JTree tree, int top, int bottom, final int row, final int previous, boolean addToSelection) { return showAndSelect(tree, top, bottom, row, previous, addToSelection, true, false); } - @NotNull - public static ActionCallback showAndSelect(@NotNull final JTree tree, int top, int bottom, final int row, final int previous, final boolean addToSelection, final boolean scroll) { + public static @NotNull ActionCallback showAndSelect(final @NotNull JTree tree, int top, int bottom, final int row, final int previous, final boolean addToSelection, final boolean scroll) { return showAndSelect(tree, top, bottom, row, previous, addToSelection, scroll, false); } - @NotNull - public static ActionCallback showAndSelect(@NotNull final JTree tree, int top, int bottom, final int row, final int previous, final boolean addToSelection, final boolean scroll, final boolean resetSelection) { + public static @NotNull ActionCallback showAndSelect(final @NotNull JTree tree, int top, int bottom, final int row, final int previous, final boolean addToSelection, final boolean scroll, final boolean resetSelection) { final TreePath path = tree.getPathForRow(row); if (path == null) return ActionCallback.DONE; @@ -766,11 +729,11 @@ public final class TreeUtil { } // this method returns FIRST selected row but not LEAD - private static int getSelectedRow(@NotNull final JTree tree) { + private static int getSelectedRow(final @NotNull JTree tree) { return tree.getRowForPath(tree.getSelectionPath()); } - private static int getFirstVisibleRow(@NotNull final JTree tree) { + private static int getFirstVisibleRow(final @NotNull JTree tree) { final Rectangle visible = tree.getVisibleRect(); int row = -1; for (int i=0; i < tree.getRowCount(); i++) { @@ -790,7 +753,7 @@ public final class TreeUtil { * @param tree tree to get the number of visible rows * @return number of visible rows, including partially visible ones. Not more than total number of tree rows. */ - public static int getVisibleRowCount(@NotNull final JTree tree) { + public static int getVisibleRowCount(final @NotNull JTree tree) { final Rectangle visible = tree.getVisibleRect(); if (visible == null) return 0; @@ -813,7 +776,7 @@ public final class TreeUtil { return lastRow - firstRow + 1; } - public static void installActions(@NotNull final JTree tree) { + public static void installActions(final @NotNull JTree tree) { TreeUI ui = tree.getUI(); if (ui != null && ui.getClass().getName().equals("com.intellij.ui.tree.ui.DefaultTreeUI")) return; tree.getActionMap().put("scrollUpChangeSelection", new AbstractAction() { @@ -852,7 +815,7 @@ public final class TreeUtil { UIUtil.maybeInstall(inputMap, "selectFirst", KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0)); } - private static void copyAction(@NotNull final JTree tree, String original, String copyTo) { + private static void copyAction(final @NotNull JTree tree, String original, String copyTo) { final Action action = tree.getActionMap().get(original); if (action != null) { tree.getActionMap().put(copyTo, action); @@ -909,8 +872,7 @@ public final class TreeUtil { * @param keepSelectionLevel a maximal number of elements in the selection path or negative value to preserve the given path * @return a parent path with the specified number of elements, or the given {@code path} if it does not have enough elements */ - @NotNull - private static TreePath normalize(@NotNull TreePath path, int minCount, int keepSelectionLevel) { + private static @NotNull TreePath normalize(@NotNull TreePath path, int minCount, int keepSelectionLevel) { if (keepSelectionLevel < 0) return path; if (keepSelectionLevel > minCount) minCount = keepSelectionLevel; int pathCount = path.getPathCount(); @@ -929,11 +891,11 @@ public final class TreeUtil { return node != null && node.isAlwaysExpand(); } - public static void selectNode(@NotNull final JTree tree, final TreeNode node) { + public static void selectNode(final @NotNull JTree tree, final TreeNode node) { selectPath(tree, getPathFromRoot(node)); } - public static void moveSelectedRow(@NotNull final JTree tree, final int direction){ + public static void moveSelectedRow(final @NotNull JTree tree, final int direction){ final TreePath selectionPath = tree.getSelectionPath(); final DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)selectionPath.getLastPathComponent(); final DefaultMutableTreeNode parent = (DefaultMutableTreeNode)treeNode.getParent(); @@ -943,8 +905,7 @@ public final class TreeUtil { selectNode(tree, treeNode); } - @NotNull - public static List listChildren(@NotNull final TreeNode node) { + public static @NotNull List listChildren(final @NotNull TreeNode node) { //ApplicationManager.getApplication().assertIsDispatchThread(); int size = node.getChildCount(); ArrayList result = new ArrayList<>(size); @@ -956,7 +917,7 @@ public final class TreeUtil { return result; } - public static void expandRootChildIfOnlyOne(@Nullable final JTree tree) { + public static void expandRootChildIfOnlyOne(final @Nullable JTree tree) { if (tree == null) return; Runnable runnable = () -> { TreeModel model = tree.getModel(); @@ -995,8 +956,7 @@ public final class TreeUtil { * @param tree a tree, which nodes should be expanded * @return a promise that will be succeeded when all nodes are expanded */ - @NotNull - public static Promise promiseExpandAll(@NotNull JTree tree) { + public static @NotNull Promise promiseExpandAll(@NotNull JTree tree) { return promiseExpand(tree, Integer.MAX_VALUE); } @@ -1030,8 +990,7 @@ public final class TreeUtil { * @param depth a depth starting from the root node * @return a promise that will be succeeded when all needed nodes are expanded */ - @NotNull - public static Promise promiseExpand(@NotNull JTree tree, int depth) { + public static @NotNull Promise promiseExpand(@NotNull JTree tree, int depth) { AsyncPromise promise = new AsyncPromise<>(); promiseMakeVisible(tree, path -> depth < path.getPathCount() ? TreeVisitor.Action.SKIP_SIBLINGS : TreeVisitor.Action.CONTINUE, promise) .onError(promise::setError) @@ -1042,13 +1001,11 @@ public final class TreeUtil { return promise; } - @NotNull - public static ActionCallback selectInTree(DefaultMutableTreeNode node, boolean requestFocus, @NotNull JTree tree) { + public static @NotNull ActionCallback selectInTree(DefaultMutableTreeNode node, boolean requestFocus, @NotNull JTree tree) { return selectInTree(node, requestFocus, tree, true); } - @NotNull - public static ActionCallback selectInTree(@Nullable DefaultMutableTreeNode node, boolean requestFocus, @NotNull JTree tree, boolean center) { + public static @NotNull ActionCallback selectInTree(@Nullable DefaultMutableTreeNode node, boolean requestFocus, @NotNull JTree tree, boolean center) { if (node == null) return ActionCallback.DONE; final TreePath treePath = new TreePath(node.getPath()); @@ -1059,8 +1016,7 @@ public final class TreeUtil { return selectPath(tree, treePath, center); } - @NotNull - public static ActionCallback selectInTree(Project project, @Nullable DefaultMutableTreeNode node, boolean requestFocus, @NotNull JTree tree, boolean center) { + public static @NotNull ActionCallback selectInTree(Project project, @Nullable DefaultMutableTreeNode node, boolean requestFocus, @NotNull JTree tree, boolean center) { if (node == null) return ActionCallback.DONE; final TreePath treePath = new TreePath(node.getPath()); @@ -1094,8 +1050,7 @@ public final class TreeUtil { * @param tree a tree, which selection is processed * @return a list of all selected paths */ - @NotNull - public static List collectSelectedPaths(@NotNull JTree tree) { + public static @NotNull List collectSelectedPaths(@NotNull JTree tree) { return collectSelectedObjects(tree, Function.identity()); } @@ -1103,8 +1058,7 @@ public final class TreeUtil { * @param tree a tree, which selection is processed * @return a list of user objects which correspond to all selected paths */ - @NotNull - public static List collectSelectedUserObjects(@NotNull JTree tree) { + public static @NotNull List collectSelectedUserObjects(@NotNull JTree tree) { return collectSelectedObjects(tree, TreeUtil::getLastUserObject); } @@ -1113,8 +1067,7 @@ public final class TreeUtil { * @param mapper a function to convert a selected tree path to a corresponding object * @return a list of objects which correspond to all selected paths */ - @NotNull - public static List collectSelectedObjects(@NotNull JTree tree, @NotNull Function mapper) { + public static @NotNull List collectSelectedObjects(@NotNull JTree tree, @NotNull Function mapper) { return getSelection(tree, path -> isViewable(tree, path), mapper); } @@ -1123,8 +1076,7 @@ public final class TreeUtil { * @param root an ascendant tree path to filter selected tree paths * @return a list of selected paths under the specified root node */ - @NotNull - public static List collectSelectedPaths(@NotNull JTree tree, @NotNull TreePath root) { + public static @NotNull List collectSelectedPaths(@NotNull JTree tree, @NotNull TreePath root) { return collectSelectedObjects(tree, root, Function.identity()); } @@ -1133,8 +1085,7 @@ public final class TreeUtil { * @param root an ascendant tree path to filter selected tree paths * @return a list of user objects which correspond to selected paths under the specified root node */ - @NotNull - public static List collectSelectedUserObjects(@NotNull JTree tree, @NotNull TreePath root) { + public static @NotNull List collectSelectedUserObjects(@NotNull JTree tree, @NotNull TreePath root) { return collectSelectedObjects(tree, root, TreeUtil::getLastUserObject); } @@ -1144,14 +1095,12 @@ public final class TreeUtil { * @param mapper a function to convert a selected tree path to a corresponding object * @return a list of objects which correspond to selected paths under the specified root node */ - @NotNull - public static List collectSelectedObjects(@NotNull JTree tree, @NotNull TreePath root, @NotNull Function mapper) { + public static @NotNull List collectSelectedObjects(@NotNull JTree tree, @NotNull TreePath root, @NotNull Function mapper) { if (!tree.isVisible(root)) return Collections.emptyList(); // invisible path should not be selected return getSelection(tree, path -> isViewable(tree, path) && root.isDescendant(path), mapper); } - @NotNull - private static List getSelection(@NotNull JTree tree, @NotNull Predicate filter, @NotNull Function mapper) { + private static @NotNull List getSelection(@NotNull JTree tree, @NotNull Predicate filter, @NotNull Function mapper) { TreePath[] paths = tree.getSelectionPaths(); if (paths == null || paths.length == 0) return Collections.emptyList(); // nothing is selected return Stream.of(paths).filter(filter).map(mapper).filter(Objects::nonNull).collect(toList()); @@ -1169,8 +1118,7 @@ public final class TreeUtil { } } - @Nullable - public static Range getExpandControlRange(@NotNull final JTree aTree, @Nullable final TreePath path) { + public static @Nullable Range getExpandControlRange(final @NotNull JTree aTree, final @Nullable TreePath path) { TreeModel treeModel = aTree.getModel(); final BasicTreeUI basicTreeUI = (BasicTreeUI)aTree.getUI(); @@ -1271,8 +1219,7 @@ public final class TreeUtil { } } - @NotNull - public static RelativePoint getPointForSelection(@NotNull JTree aTree) { + public static @NotNull RelativePoint getPointForSelection(@NotNull JTree aTree) { final int[] rows = aTree.getSelectionRows(); if (rows == null || rows.length == 0) { return RelativePoint.getCenterOf(aTree); @@ -1280,24 +1227,21 @@ public final class TreeUtil { return getPointForRow(aTree, rows[rows.length - 1]); } - @NotNull - public static RelativePoint getPointForRow(@NotNull JTree aTree, int aRow) { + public static @NotNull RelativePoint getPointForRow(@NotNull JTree aTree, int aRow) { return getPointForPath(aTree, aTree.getPathForRow(aRow)); } - @NotNull - public static RelativePoint getPointForPath(@NotNull JTree aTree, TreePath path) { + public static @NotNull RelativePoint getPointForPath(@NotNull JTree aTree, TreePath path) { final Rectangle rowBounds = aTree.getPathBounds(path); rowBounds.x += 20; return getPointForBounds(aTree, rowBounds); } - @NotNull - public static RelativePoint getPointForBounds(JComponent aComponent, @NotNull final Rectangle aBounds) { + public static @NotNull RelativePoint getPointForBounds(JComponent aComponent, final @NotNull Rectangle aBounds) { return new RelativePoint(aComponent, new Point(aBounds.x, (int)aBounds.getMaxY())); } - public static boolean isOverSelection(@NotNull final JTree tree, @NotNull final Point point) { + public static boolean isOverSelection(final @NotNull JTree tree, final @NotNull Point point) { TreePath path = tree.getPathForLocation(point.x, point.y); return path != null && tree.getSelectionModel().isPathSelected(path); } @@ -1327,13 +1271,11 @@ public final class TreeUtil { return false; } - @Nullable - public static Object getUserObject(@Nullable Object node) { + public static @Nullable Object getUserObject(@Nullable Object node) { return node instanceof DefaultMutableTreeNode ? ((DefaultMutableTreeNode)node).getUserObject() : node; } - @Nullable - public static T getUserObject(@NotNull Class type, @Nullable Object node) { + public static @Nullable T getUserObject(@NotNull Class type, @Nullable Object node) { node = getUserObject(node); return type.isInstance(node) ? type.cast(node) : null; } @@ -1341,13 +1283,11 @@ public final class TreeUtil { /** * @return a user object retrieved from the last component of the specified {@code path} */ - @Nullable - public static Object getLastUserObject(@Nullable TreePath path) { + public static @Nullable Object getLastUserObject(@Nullable TreePath path) { return path == null ? null : getUserObject(path.getLastPathComponent()); } - @Nullable - public static T getLastUserObject(@NotNull Class type, @Nullable TreePath path) { + public static @Nullable T getLastUserObject(@NotNull Class type, @Nullable TreePath path) { return path == null ? null : getUserObject(type, path.getLastPathComponent()); } @@ -1428,8 +1368,7 @@ public final class TreeUtil { return ObjectUtils.binarySearch(0, parent.getChildCount(), mid -> comparator.compare((T)parent.getChildAt(mid), key)); } - @NotNull - public static Comparator getDisplayOrderComparator(@NotNull final JTree tree) { + public static @NotNull Comparator getDisplayOrderComparator(final @NotNull JTree tree) { return Comparator.comparingInt(tree::getRowForPath); } @@ -1476,8 +1415,7 @@ public final class TreeUtil { * @param visitor a visitor that controls expanding of tree nodes * @return a promise that will be succeeded only if path is found and expanded */ - @NotNull - public static Promise promiseExpand(@NotNull JTree tree, @NotNull TreeVisitor visitor) { + public static @NotNull Promise promiseExpand(@NotNull JTree tree, @NotNull TreeVisitor visitor) { return promiseMakeVisibleOne(tree, visitor, path -> expandPathWithDebug(tree, path)); } @@ -1491,8 +1429,7 @@ public final class TreeUtil { * @param visitors visitors to control expanding of tree nodes * @return a promise that will be succeeded only if paths are found and expanded */ - @NotNull - public static Promise> promiseExpand(@NotNull JTree tree, @NotNull Stream visitors) { + public static @NotNull Promise> promiseExpand(@NotNull JTree tree, @NotNull Stream visitors) { return promiseMakeVisibleAll(tree, visitors, paths -> paths.forEach(path -> expandPathWithDebug(tree, path))); } @@ -1531,20 +1468,20 @@ public final class TreeUtil { * @param visitor a visitor that controls expanding of tree nodes * @return a promise that will be succeeded only if path is found and made visible */ - @NotNull - public static Promise promiseMakeVisible(@NotNull JTree tree, @NotNull TreeVisitor visitor) { + public static @NotNull Promise promiseMakeVisible(@NotNull JTree tree, @NotNull TreeVisitor visitor) { return promiseMakeVisibleOne(tree, visitor, null); } - @NotNull - private static Promise promiseMakeVisibleOne(@NotNull JTree tree, - @NotNull TreeVisitor visitor, - @Nullable Consumer consumer) { + private static @NotNull Promise promiseMakeVisibleOne(@NotNull JTree tree, + @NotNull TreeVisitor visitor, + @Nullable Consumer consumer) { AsyncPromise promise = new AsyncPromise<>(); promiseMakeVisible(tree, visitor, promise) .onError(promise::setError) .onSuccess(path -> { - if (promise.isCancelled()) return; + if (promise.isCancelled()) { + return; + } UIUtil.invokeLaterIfNeeded(() -> { if (promise.isCancelled()) return; if (tree.isVisible(path)) { @@ -1569,9 +1506,8 @@ public final class TreeUtil { * @param visitors visitors to control expanding of tree nodes * @return a promise that will be succeeded only if path are found and made visible */ - @NotNull @SuppressWarnings("unused") - public static Promise> promiseMakeVisible(@NotNull JTree tree, @NotNull Stream visitors) { + public static @NotNull Promise> promiseMakeVisible(@NotNull JTree tree, @NotNull Stream visitors) { return promiseMakeVisibleAll(tree, visitors, null); } @@ -1607,8 +1543,7 @@ public final class TreeUtil { return promise; } - @NotNull - private static Promise promiseMakeVisible(@NotNull JTree tree, @NotNull TreeVisitor visitor, @NotNull AsyncPromise promise) { + private static @NotNull Promise promiseMakeVisible(@NotNull JTree tree, @NotNull TreeVisitor visitor, @NotNull AsyncPromise promise) { return promiseVisit(tree, path -> { if (promise.isCancelled()) return TreeVisitor.Action.SKIP_SIBLINGS; TreeVisitor.Action action = visitor.visit(path); @@ -1651,8 +1586,7 @@ public final class TreeUtil { * @param visitor a visitor that controls expanding of tree nodes * @return a promise that will be succeeded only if path is found and selected */ - @NotNull - public static Promise promiseSelect(@NotNull JTree tree, @NotNull TreeVisitor visitor) { + public static @NotNull Promise promiseSelect(@NotNull JTree tree, @NotNull TreeVisitor visitor) { return promiseMakeVisibleOne(tree, visitor, path -> internalSelect(tree, path)); } @@ -1666,8 +1600,7 @@ public final class TreeUtil { * @param visitors visitors to control expanding of tree nodes * @return a promise that will be succeeded only if paths are found and selected */ - @NotNull - public static Promise> promiseSelect(@NotNull JTree tree, @NotNull Stream visitors) { + public static @NotNull Promise> promiseSelect(@NotNull JTree tree, @NotNull Stream visitors) { return promiseMakeVisibleAll(tree, visitors, paths -> internalSelect(tree, paths.toArray(EMPTY_TREE_PATH))); } @@ -1757,8 +1690,7 @@ public final class TreeUtil { * @param tree a tree, which node should be selected * @return a promise that will be succeeded when first visible node is selected */ - @NotNull - public static Promise promiseSelectFirst(@NotNull JTree tree) { + public static @NotNull Promise promiseSelectFirst(@NotNull JTree tree) { return promiseSelect(tree, path -> isHiddenRoot(tree, path) ? TreeVisitor.Action.CONTINUE : TreeVisitor.Action.INTERRUPT); @@ -1777,8 +1709,7 @@ public final class TreeUtil { * @param tree a tree, which node should be selected * @return a promise that will be succeeded when first leaf node is made visible and selected */ - @NotNull - public static Promise promiseSelectFirstLeaf(@NotNull JTree tree) { + public static @NotNull Promise promiseSelectFirstLeaf(@NotNull JTree tree) { AtomicReference reference = new AtomicReference<>(); AsyncPromise promise = new AsyncPromise<>(); promiseMakeVisible(tree, path -> { @@ -1829,8 +1760,7 @@ public final class TreeUtil { * @param visitor a visitor that controls processing of tree nodes * @return a promise that will be succeeded when visiting is finished */ - @NotNull - public static Promise promiseVisit(@NotNull JTree tree, @NotNull TreeVisitor visitor) { + public static @NotNull Promise promiseVisit(@NotNull JTree tree, @NotNull TreeVisitor visitor) { TreeModel model = tree.getModel(); if (model instanceof TreeVisitor.Acceptor) { TreeVisitor.Acceptor acceptor = (TreeVisitor.Acceptor)model; @@ -1892,8 +1822,7 @@ public final class TreeUtil { return null; } - @NotNull - private static Deque children(@NotNull TreeModel model, @NotNull TreePath path) { + private static @NotNull Deque children(@NotNull TreeModel model, @NotNull TreePath path) { Object object = path.getLastPathComponent(); int count = model.getChildCount(object); Deque deque = new ArrayDeque<>(count); diff --git a/platform/platform-impl/src/com/intellij/ide/errorTreeView/ErrorViewStructure.java b/platform/platform-impl/src/com/intellij/ide/errorTreeView/ErrorViewStructure.java index 8eaca0483e24..010b5e1ff120 100644 --- a/platform/platform-impl/src/com/intellij/ide/errorTreeView/ErrorViewStructure.java +++ b/platform/platform-impl/src/com/intellij/ide/errorTreeView/ErrorViewStructure.java @@ -209,29 +209,30 @@ public class ErrorViewStructure extends AbstractTreeStructure { int line, int column, @Nullable Object data) { - if (underFileGroup != null || file != null) { - if (file == null) { - line = column = -1; - } - - final int guiline = line < 0 ? -1 : line + 1; - final int guicolumn = column < 0 ? -1 : column + 1; - - VirtualFile group = underFileGroup != null ? underFileGroup : file; - VirtualFile nav = file != null ? file : underFileGroup; - - return addNavigatableMessage( - group.getPresentableUrl(), - new OpenFileDescriptor(myProject, nav, line, column), - kind, - text, - data, - NewErrorTreeViewPanel.createExportPrefix(guiline), - NewErrorTreeViewPanel.createRendererPrefix(guiline, guicolumn), - group - ); + if (underFileGroup == null && file == null) { + return addSimpleMessageElement(new SimpleMessageElement(kind, text, data)); } - return addSimpleMessage(kind, text, data); + + if (file == null) { + line = -1; + column = -1; + } + + final int guiLine = line < 0 ? -1 : line + 1; + final int guiColumn = column < 0 ? -1 : column + 1; + + VirtualFile group = underFileGroup == null ? file : underFileGroup; + VirtualFile nav = file == null ? underFileGroup : file; + return addNavigatableMessage( + group.getPresentableUrl(), + new OpenFileDescriptor(myProject, nav, line, column), + kind, + text, + data, + NewErrorTreeViewPanel.createExportPrefix(guiLine), + NewErrorTreeViewPanel.createRendererPrefix(guiLine, guiColumn), + group + ); } public List getGroupChildrenData(final String groupName) { @@ -315,13 +316,13 @@ public class ErrorViewStructure extends AbstractTreeStructure { } public ErrorTreeElement addNavigatableMessage(@Nullable String groupName, - Navigatable navigatable, - @NotNull ErrorTreeElementKind kind, - final String[] message, - final Object data, - String exportText, - String rendererTextPrefix, - VirtualFile file) { + Navigatable navigatable, + @NotNull ErrorTreeElementKind kind, + final String[] message, + final Object data, + String exportText, + String rendererTextPrefix, + VirtualFile file) { if (groupName == null) { return addSimpleMessageElement(new NavigatableMessageElement(kind, null, message, navigatable, exportText, rendererTextPrefix)); } @@ -331,7 +332,7 @@ public class ErrorViewStructure extends AbstractTreeStructure { elements = new ArrayList<>(); myGroupNameToMessagesMap.put(groupName, elements); } - final NavigatableMessageElement element = new NavigatableMessageElement( + NavigatableMessageElement element = new NavigatableMessageElement( kind, getGroupingElement(groupName, data, file), message, navigatable, exportText, rendererTextPrefix ); elements.add(element); @@ -354,7 +355,6 @@ public class ErrorViewStructure extends AbstractTreeStructure { } } - private ErrorTreeElement addSimpleMessage(@NotNull ErrorTreeElementKind kind, final String[] text, final Object data) { return addSimpleMessageElement(new SimpleMessageElement(kind, text, data)); } diff --git a/platform/platform-impl/src/com/intellij/ide/errorTreeView/NewErrorTreeViewPanel.kt b/platform/platform-impl/src/com/intellij/ide/errorTreeView/NewErrorTreeViewPanel.kt index 770b6ad7a6f2..e9815a5e148a 100644 --- a/platform/platform-impl/src/com/intellij/ide/errorTreeView/NewErrorTreeViewPanel.kt +++ b/platform/platform-impl/src/com/intellij/ide/errorTreeView/NewErrorTreeViewPanel.kt @@ -1,585 +1,564 @@ // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.ide.errorTreeView; +package com.intellij.ide.errorTreeView -import com.intellij.icons.AllIcons; -import com.intellij.ide.*; -import com.intellij.ide.actions.CloseTabToolbarAction; -import com.intellij.ide.actions.ExportToTextFileToolbarAction; -import com.intellij.ide.errorTreeView.impl.ErrorTreeViewConfiguration; -import com.intellij.ide.errorTreeView.impl.ErrorViewTextExporter; -import com.intellij.ide.util.treeView.NodeDescriptor; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.application.TransactionGuard; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.fileEditor.OpenFileDescriptor; -import com.intellij.openapi.ide.CopyPasteManager; -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.DumbAwareAction; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.NlsContexts; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.pom.Navigatable; -import com.intellij.ui.AutoScrollToSourceHandler; -import com.intellij.ui.IdeBorderFactory; -import com.intellij.ui.PopupHandler; -import com.intellij.ui.SideBorder; -import com.intellij.ui.content.Content; -import com.intellij.ui.content.MessageView; -import com.intellij.ui.tree.AsyncTreeModel; -import com.intellij.ui.tree.StructureTreeModel; -import com.intellij.ui.treeStructure.Tree; -import com.intellij.util.Alarm; -import com.intellij.util.EditSourceOnDoubleClickHandler; -import com.intellij.util.EditSourceOnEnterKeyHandler; -import com.intellij.util.ObjectUtils; -import com.intellij.util.ui.JBUI; -import com.intellij.util.ui.MutableErrorTreeView; -import com.intellij.util.ui.StatusText; -import com.intellij.util.ui.tree.TreeUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import com.intellij.icons.AllIcons +import com.intellij.ide.* +import com.intellij.ide.actions.CloseTabToolbarAction +import com.intellij.ide.actions.ExportToTextFileToolbarAction +import com.intellij.ide.errorTreeView.impl.ErrorTreeViewConfiguration +import com.intellij.ide.errorTreeView.impl.ErrorViewTextExporter +import com.intellij.openapi.Disposable +import com.intellij.openapi.actionSystem.* +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.EDT +import com.intellij.openapi.application.createSupervisorCoroutineScope +import com.intellij.openapi.diagnostic.logger +import com.intellij.openapi.fileEditor.OpenFileDescriptor +import com.intellij.openapi.ide.CopyPasteManager +import com.intellij.openapi.project.DumbAware +import com.intellij.openapi.project.DumbAwareAction +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Disposer +import com.intellij.openapi.util.NlsContexts +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.pom.Navigatable +import com.intellij.ui.AutoScrollToSourceHandler +import com.intellij.ui.IdeBorderFactory +import com.intellij.ui.PopupHandler +import com.intellij.ui.SideBorder +import com.intellij.ui.content.MessageView +import com.intellij.ui.tree.AsyncTreeModel +import com.intellij.ui.tree.StructureTreeModel +import com.intellij.ui.treeStructure.Tree +import com.intellij.util.EditSourceOnDoubleClickHandler +import com.intellij.util.EditSourceOnEnterKeyHandler +import com.intellij.util.ui.ErrorTreeView +import com.intellij.util.ui.JBUI +import com.intellij.util.ui.MutableErrorTreeView +import com.intellij.util.ui.StatusText +import com.intellij.util.ui.tree.TreeUtil +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.debounce +import org.jetbrains.annotations.ApiStatus +import java.awt.BorderLayout +import java.awt.Component +import java.awt.GridLayout +import java.awt.datatransfer.StringSelection +import java.util.concurrent.CompletableFuture +import java.util.function.Consumer +import javax.swing.JComponent +import javax.swing.JLabel +import javax.swing.JPanel +import javax.swing.tree.DefaultMutableTreeNode +import kotlin.time.Duration.Companion.milliseconds -import javax.swing.*; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.TreePath; -import java.awt.*; -import java.awt.datatransfer.StringSelection; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CompletableFuture; +@OptIn(FlowPreview::class) +open class NewErrorTreeViewPanel @JvmOverloads constructor( + @JvmField protected var myProject: Project, + private val helpId: String?, + @Suppress("UNUSED_PARAMETER") createExitAction: Boolean = true, + createToolbar: Boolean = true, + rerunAction: Runnable? = null, + private val state: MessageViewState = MessageViewState(), + errorViewStructure: ErrorViewStructure? = null, +) : JPanel(), DataProvider, OccurenceNavigator, MutableErrorTreeView, CopyProvider, Disposable { + @ApiStatus.Internal + @ApiStatus.Experimental + class MessageViewState { + @Volatile + @JvmField + var progressText: @NlsContexts.ProgressText String? = null -public class NewErrorTreeViewPanel extends JPanel implements DataProvider, OccurenceNavigator, MutableErrorTreeView, CopyProvider, Disposable { - protected static final Logger LOG = Logger.getInstance(NewErrorTreeViewPanel.class); - private volatile @NlsContexts.ProgressText String myProgressText = ""; - private volatile float myFraction; - private final ErrorViewStructure myErrorViewStructure; - private final StructureTreeModel myStructureModel; - private final Alarm myUpdateAlarm = new Alarm(); - private volatile boolean myIsDisposed; - private final ErrorTreeViewConfiguration myConfiguration; + @JvmField + @Volatile + var fraction = 0f - public interface ProcessController { - void stopProcess(); - - boolean isProcessStopped(); + fun clearProgress() { + progressText = null + fraction = 0.0f + } } - private ActionToolbar myLeftToolbar; - private final TreeExpander myTreeExpander = new MyTreeExpander(); - private final ExporterToTextFile myExporterToTextFile; - protected Project myProject; - private final String myHelpId; - protected Tree myTree; - private final JPanel myMessagePanel; - private ProcessController myProcessController; + val errorViewStructure: ErrorViewStructure - private JLabel myProgressLabel; - private JPanel myProgressPanel; + private val structureModel: StructureTreeModel + private val progressFlow = MutableStateFlow(null) - private final AutoScrollToSourceHandler myAutoScrollToSourceHandler; - private final MyOccurrenceNavigatorSupport myOccurrenceNavigatorSupport; + @Volatile + private var isDisposed = false + private val configuration = ErrorTreeViewConfiguration.getInstance(myProject) - public NewErrorTreeViewPanel(Project project, String helpId) { - this(project, helpId, true); + private var leftToolbar: ActionToolbar? = null + + private val treeExpander = object : TreeExpander { + override fun expandAll() { + this@NewErrorTreeViewPanel.expandAll() + } + + override fun canExpand() = true + + override fun collapseAll() { + this@NewErrorTreeViewPanel.collapseAll() + } + + override fun canCollapse() = true } - public NewErrorTreeViewPanel(Project project, String helpId, boolean createExitAction) { - this(project, helpId, createExitAction, true); + private val exporterToTextFile: ExporterToTextFile + @JvmField + protected var myTree: Tree + private val messagePanel: JPanel + private var processController: ProcessController? = null + private var progressLabel: JLabel? = null + private var progressPanel: JPanel? = null + private val autoScrollToSourceHandler: AutoScrollToSourceHandler + private val occurrenceNavigatorSupport: MyOccurrenceNavigatorSupport + + interface ProcessController { + fun stopProcess() + + val isProcessStopped: Boolean } - public NewErrorTreeViewPanel(Project project, String helpId, boolean createExitAction, boolean createToolbar) { - this(project, helpId, createExitAction, createToolbar, null); - } + private val scope = createSupervisorCoroutineScope(myProject.coroutineScope) - public NewErrorTreeViewPanel(Project project, String helpId, boolean createExitAction, boolean createToolbar, @Nullable Runnable rerunAction) { - myProject = project; - myHelpId = helpId; - myConfiguration = ErrorTreeViewConfiguration.getInstance(project); - setLayout(new BorderLayout()); + init { + layout = BorderLayout() + autoScrollToSourceHandler = object : AutoScrollToSourceHandler() { + override fun isAutoScrollMode() = configuration.isAutoscrollToSource - myAutoScrollToSourceHandler = new AutoScrollToSourceHandler() { - @Override - protected boolean isAutoScrollMode() { - return myConfiguration.isAutoscrollToSource(); + override fun setAutoScrollMode(state: Boolean) { + configuration.isAutoscrollToSource = state } - - @Override - protected void setAutoScrollMode(boolean state) { - myConfiguration.setAutoscrollToSource(state); - } - }; - - myMessagePanel = new JPanel(new BorderLayout()); - - myErrorViewStructure = createErrorViewStructure(project, canHideWarnings()); - myStructureModel = new StructureTreeModel<>(myErrorViewStructure, this); - myTree = new Tree(new AsyncTreeModel(myStructureModel, this)); - myTree.setRowHeight(0); - myTree.getEmptyText().setText(IdeBundle.message("errortree.noMessages")); - - myExporterToTextFile = new ErrorViewTextExporter(myErrorViewStructure); - myOccurrenceNavigatorSupport = new MyOccurrenceNavigatorSupport(myTree); - - myAutoScrollToSourceHandler.install(myTree); - TreeUtil.installActions(myTree); - myTree.setRootVisible(false); - myTree.setShowsRootHandles(true); - myTree.setLargeModel(true); - - JScrollPane scrollPane = NewErrorTreeRenderer.install(myTree); - scrollPane.setBorder(IdeBorderFactory.createBorder(SideBorder.LEFT)); - myMessagePanel.add(scrollPane, BorderLayout.CENTER); - + } + messagePanel = JPanel(BorderLayout()) + @Suppress("LeakingThis") + this.errorViewStructure = errorViewStructure ?: createErrorViewStructure(project = myProject, canHideWarnings = canHideWarnings()) + @Suppress("LeakingThis") + structureModel = StructureTreeModel(this.errorViewStructure, this) + @Suppress("LeakingThis") + myTree = Tree(AsyncTreeModel(structureModel, this)) + myTree.rowHeight = 0 + @Suppress("SpellCheckingInspection") + myTree.emptyText.text = IdeBundle.message("errortree.noMessages") + exporterToTextFile = ErrorViewTextExporter(errorViewStructure) + occurrenceNavigatorSupport = MyOccurrenceNavigatorSupport(myTree) + autoScrollToSourceHandler.install(myTree) + TreeUtil.installActions(myTree) + myTree.isRootVisible = false + myTree.showsRootHandles = true + myTree.isLargeModel = true + val scrollPane = NewErrorTreeRenderer.install(myTree) + scrollPane.border = IdeBorderFactory.createBorder(SideBorder.LEFT) + messagePanel.add(scrollPane, BorderLayout.CENTER) if (createToolbar) { - add(createToolbarPanel(rerunAction), BorderLayout.WEST); + @Suppress("LeakingThis") + add(createToolbarPanel(rerunAction), BorderLayout.WEST) } - - add(myMessagePanel, BorderLayout.CENTER); - - myTree.addMouseListener(new PopupHandler() { - @Override - public void invokePopup(Component comp, int x, int y) { - popupInvoked(comp, x, y); + @Suppress("LeakingThis") + add(messagePanel, BorderLayout.CENTER) + myTree.addMouseListener(object : PopupHandler() { + override fun invokePopup(comp: Component, x: Int, y: Int) { + popupInvoked(comp, x, y) } - }); + }) + EditSourceOnDoubleClickHandler.install(myTree) + EditSourceOnEnterKeyHandler.install(myTree) - EditSourceOnDoubleClickHandler.install(myTree); - EditSourceOnEnterKeyHandler.install(myTree); - } - - protected ErrorViewStructure createErrorViewStructure(Project project, boolean canHideWarnings) { - return new ErrorViewStructure(project, canHideWarnings); - } - - @Override - public void dispose() { - myIsDisposed = true; - myErrorViewStructure.clear(); - myUpdateAlarm.cancelAllRequests(); - Disposer.dispose(myUpdateAlarm); - } - - @Override - public void performCopy(@NotNull DataContext dataContext) { - List descriptors = getSelectedNodeDescriptors(); - if (!descriptors.isEmpty()) { - CopyPasteManager.getInstance().setContents(new StringSelection(StringUtil.join(descriptors, descriptor -> { - ErrorTreeElement element = descriptor.getElement(); - return NewErrorTreeRenderer.calcPrefix(element) + StringUtil.join(element.getText(), "\n"); - }, "\n"))); - } - } - - @Override - public @NotNull ActionUpdateThread getActionUpdateThread() { - return ActionUpdateThread.EDT; - } - - @Override - public boolean isCopyEnabled(@NotNull DataContext dataContext) { - return !getSelectedNodeDescriptors().isEmpty(); - } - - @Override - public boolean isCopyVisible(@NotNull DataContext dataContext) { - return true; - } - - public @NotNull StatusText getEmptyText() { - return myTree.getEmptyText(); - } - - @Override - public Object getData(@NotNull String dataId) { - if (PlatformDataKeys.COPY_PROVIDER.is(dataId)) { - return this; - } - if (CommonDataKeys.NAVIGATABLE.is(dataId)) { - final NavigatableErrorTreeElement selectedMessageElement = getSelectedNavigatableElement(); - return selectedMessageElement != null ? selectedMessageElement.getNavigatable() : null; - } - else if (PlatformCoreDataKeys.HELP_ID.is(dataId)) { - return myHelpId; - } - else if (PlatformDataKeys.TREE_EXPANDER.is(dataId)) { - return myTreeExpander; - } - else if (PlatformDataKeys.EXPORTER_TO_TEXT_FILE.is(dataId)) { - return myExporterToTextFile; - } - else if (CURRENT_EXCEPTION_DATA_KEY.is(dataId)) { - ErrorTreeElement selectedMessageElement = getSelectedErrorTreeElement(); - return selectedMessageElement != null ? selectedMessageElement.getData() : null; - } - return null; - } - - public void selectFirstMessage() { - final ErrorTreeElement firstError = myErrorViewStructure.getFirstMessage(ErrorTreeElementKind.ERROR); - if (firstError != null) { - selectElement(firstError, () -> { - if (shouldShowFirstErrorInEditor()) { - TransactionGuard.submitTransaction(this, () -> navigateToSource(false)); + scope.launch { + progressFlow + .debounce(100.milliseconds) + .collectLatest { text -> + withContext(Dispatchers.EDT) { + initProgressPanel() + if (text == null) { + progressLabel!!.text = "" + } + else { + val fraction = state.fraction + progressLabel!!.text = if (fraction > 0.0f) "${(fraction * 100 + 0.5).toInt()}% $text" else text + } + } } - }); + } + } + + companion object { + @JvmField + protected val LOG = logger() + + @Suppress("SpellCheckingInspection") + @JvmStatic + fun createExportPrefix(line: Int): String = if (line < 0) "" else IdeBundle.message("errortree.prefix.line", line) + + @JvmStatic + fun createRendererPrefix(line: Int, column: Int): String { + if (line < 0) { + return "" + } + return if (column < 0) "($line)" else "($line, $column)" + } + + @JvmStatic + fun getQualifiedName(file: VirtualFile): String = file.presentableUrl + } + + protected open fun createErrorViewStructure(project: Project?, canHideWarnings: Boolean): ErrorViewStructure { + return ErrorViewStructure(project, canHideWarnings) + } + + override fun dispose() { + try { + scope.cancel() + } + finally { + isDisposed = true + errorViewStructure.clear() + } + } + + override fun performCopy(dataContext: DataContext) { + val descriptors = selectedNodeDescriptors + if (!descriptors.isEmpty()) { + CopyPasteManager.getInstance().setContents(StringSelection(descriptors.joinToString(separator = "\n") { + val element = it.element + NewErrorTreeRenderer.calcPrefix(element) + element.text.joinToString(separator = "\n") + })) + } + } + + override fun getActionUpdateThread() = ActionUpdateThread.EDT + + override fun isCopyEnabled(dataContext: DataContext) = !selectedNodeDescriptors.isEmpty() + + override fun isCopyVisible(dataContext: DataContext) = true + + val emptyText: StatusText + get() = myTree.emptyText + + override fun getData(dataId: String): Any? { + return when { + PlatformDataKeys.COPY_PROVIDER.`is`(dataId) -> this + CommonDataKeys.NAVIGATABLE.`is`(dataId) -> { + val selectedMessageElement = selectedNavigatableElement + selectedMessageElement?.navigatable + } + PlatformCoreDataKeys.HELP_ID.`is`(dataId) -> helpId + PlatformDataKeys.TREE_EXPANDER.`is`(dataId) -> treeExpander + PlatformDataKeys.EXPORTER_TO_TEXT_FILE.`is`(dataId) -> exporterToTextFile + ErrorTreeView.CURRENT_EXCEPTION_DATA_KEY.`is`(dataId) -> { + val selectedMessageElement = selectedErrorTreeElement + selectedMessageElement?.data + } + else -> null + } + } + + open fun selectFirstMessage() { + val firstError = errorViewStructure.getFirstMessage(ErrorTreeElementKind.ERROR) + if (firstError != null) { + selectElement(firstError) { + if (shouldShowFirstErrorInEditor()) { + ApplicationManager.getApplication().invokeLater(::navigateToSource, myProject.disposed) + } + } } else { - ErrorTreeElement firstWarning = myErrorViewStructure.getFirstMessage(ErrorTreeElementKind.WARNING); - if (firstWarning == null) firstWarning = myErrorViewStructure.getFirstMessage(ErrorTreeElementKind.NOTE); - - if (firstWarning != null) { - selectElement(firstWarning, null); + val firstWarning = errorViewStructure.getFirstMessage(ErrorTreeElementKind.WARNING) + ?: errorViewStructure.getFirstMessage(ErrorTreeElementKind.NOTE) + if (firstWarning == null) { + TreeUtil.promiseSelectFirst(myTree) } else { - TreeUtil.promiseSelectFirst(myTree); + selectElement(firstWarning, null) } } } - private void selectElement(final ErrorTreeElement element, final @Nullable Runnable onDone) { - myStructureModel.select(element, myTree, onDone == null? path -> {} : path -> onDone.run()); + private fun selectElement(element: ErrorTreeElement, onDone: Runnable?) { + structureModel.select(element, myTree, Consumer { onDone?.run() }) } - protected boolean shouldShowFirstErrorInEditor() { - return false; - } + protected open fun shouldShowFirstErrorInEditor(): Boolean = false - public void updateTree() { - if (!myIsDisposed) { - myStructureModel.invalidateAsync(); + open fun updateTree() { + if (!isDisposed) { + structureModel.invalidateAsync() } } - @Override - public void addMessage(int type, String @NotNull [] text, @Nullable VirtualFile file, int line, int column, @Nullable Object data) { - addMessage(type, text, null, file, line, column, data); + override fun addMessage(type: Int, text: Array, file: VirtualFile?, line: Int, column: Int, data: Any?) { + addMessage(type = type, text = text, underFileGroup = null, file = file, line = line, column = column, data = data) } - @Override - public void addMessage(int type, - String @NotNull [] text, - @Nullable VirtualFile underFileGroup, - @Nullable VirtualFile file, - int line, - int column, - @Nullable Object data) { - if (myIsDisposed) { - return; + override fun addMessage(type: Int, + text: Array, + underFileGroup: VirtualFile?, + file: VirtualFile?, + line: Int, + column: Int, + data: Any?) { + if (isDisposed) { + return } - updateAddedElement(myErrorViewStructure.addMessage( + updateAddedElement(errorViewStructure.addMessage( ErrorTreeElementKind.convertMessageFromCompilerErrorType(type), text, underFileGroup, file, line, column, data - )); + )) } - protected void updateAddedElement(@NotNull ErrorTreeElement element) { - CompletableFuture future; - Object parent = myErrorViewStructure.getParentElement(element); + fun updateAddedElement(element: ErrorTreeElement) { + var future: CompletableFuture<*>? + val parent = errorViewStructure.getParentElement(element) if (parent == null) { - future = myStructureModel.invalidateAsync(); + future = structureModel.invalidateAsync() } else { - if (parent instanceof GroupingElement) { - Object parent2 = myErrorViewStructure.getParentElement(parent); + future = if (parent is GroupingElement) { + val parent2 = errorViewStructure.getParentElement(parent) // first, need to invalidate GroupingElement itself as it may have been just added - future = parent2 == null ? null : myStructureModel.invalidateAsync(parent2, true); + if (parent2 == null) null else structureModel.invalidateAsync(parent2, true) } else { - future = null; + null } if (future == null) { - future = myStructureModel.invalidateAsync(parent, true); + future = structureModel.invalidateAsync(parent, true) } else { future = future // invalidateAsync for parent in any case - .handle((o, throwable) -> null) - .thenCompose(__ -> myStructureModel.invalidateAsync(parent, true)); + .handle { _, _ -> null } + .thenCompose { structureModel.invalidateAsync(parent, true) } } } - if (element.getKind() == ErrorTreeElementKind.ERROR) { + if (element.kind == ErrorTreeElementKind.ERROR) { // expand automatically only errors - future.thenRun(() -> makeVisible(element)); + future!!.thenRun { makeVisible(element) } } } - protected void makeVisible(@NotNull ErrorTreeElement element) { - myStructureModel.makeVisible(element, myTree, pp->{}); + protected fun makeVisible(element: ErrorTreeElement) { + structureModel.makeVisible(element, myTree) { } } - @Override - public void addMessage(int type, - String @NotNull [] text, - @Nullable String groupName, - @NotNull Navigatable navigatable, - @Nullable String exportTextPrefix, - @Nullable String rendererTextPrefix, - @Nullable Object data) { - if (myIsDisposed) { - return; + override fun addMessage(type: Int, + text: Array, + groupName: String?, + navigatable: Navigatable, + exportTextPrefix: String?, + rendererTextPrefix: String?, + data: Any?) { + if (isDisposed) { + return } - VirtualFile file = data instanceof VirtualFile ? (VirtualFile)data : null; - if (file == null && navigatable instanceof OpenFileDescriptor) { - file = ((OpenFileDescriptor)navigatable).getFile(); + + var file = if (data is VirtualFile) data else null + if (file == null && navigatable is OpenFileDescriptor) { + file = navigatable.file } - final String exportPrefix = exportTextPrefix == null ? "" : exportTextPrefix; - final String renderPrefix = rendererTextPrefix == null ? "" : rendererTextPrefix; - final ErrorTreeElementKind kind = ErrorTreeElementKind.convertMessageFromCompilerErrorType(type); - updateAddedElement(myErrorViewStructure.addNavigatableMessage( + val exportPrefix = exportTextPrefix ?: "" + val renderPrefix = rendererTextPrefix ?: "" + val kind = ErrorTreeElementKind.convertMessageFromCompilerErrorType(type) + updateAddedElement(errorViewStructure.addNavigatableMessage( groupName, navigatable, kind, text, data, exportPrefix, renderPrefix, file - )); + )) } - public boolean removeMessage(int type, @NotNull String groupName, @NotNull Navigatable navigatable) { - final ErrorTreeElementKind kind = ErrorTreeElementKind.convertMessageFromCompilerErrorType(type); - List removed = myErrorViewStructure.removeNavigatableMessage(groupName, kind, navigatable); - if (removed.isEmpty()) return false; - removed.forEach(this::updateAddedElement); - return true; + fun removeMessage(type: Int, groupName: String, navigatable: Navigatable): Boolean { + val kind = ErrorTreeElementKind.convertMessageFromCompilerErrorType(type) + val removed = errorViewStructure.removeNavigatableMessage(groupName, kind, navigatable) + if (removed.isEmpty()) { + return false + } + for (descriptor in removed) { + updateAddedElement(descriptor) + } + return true } - public void removeAllInGroup(@NotNull String name) { - List removed = myErrorViewStructure.removeAllNavigatableMessagesInGroup(name); - removed.forEach(this::updateAddedElement); + fun removeAllInGroup(name: String) { + for (it in errorViewStructure.removeAllNavigatableMessagesInGroup(name)) { + updateAddedElement(it) + } } - public NavigatableMessageElement @Nullable [] getNavigatableMessages(@NotNull String groupName) { - ErrorTreeElement[] childElements = myErrorViewStructure.getChildElements(new GroupingElement(groupName, null, null)); - return ObjectUtils.tryCast(childElements, NavigatableMessageElement[].class); - } + override fun getComponent(): JComponent = this - public ErrorViewStructure getErrorViewStructure() { - return myErrorViewStructure; - } + private val selectedNavigatableElement: NavigatableErrorTreeElement? + get() = selectedErrorTreeElement as? NavigatableErrorTreeElement - public static String createExportPrefix(int line) { - return line < 0 ? "" : IdeBundle.message("errortree.prefix.line", line); - } + val selectedErrorTreeElement: ErrorTreeElement? + get() = selectedNodeDescriptor?.element - public static String createRendererPrefix(int line, int column) { - if (line < 0) return ""; - if (column < 0) return "(" + line + ")"; - return "(" + line + ", " + column + ")"; - } + private val selectedNodeDescriptor: ErrorTreeNodeDescriptor? + get() = selectedNodeDescriptors.singleOrNull() - @Override - public @NotNull JComponent getComponent() { - return this; - } - - private @Nullable NavigatableErrorTreeElement getSelectedNavigatableElement() { - final ErrorTreeElement selectedElement = getSelectedErrorTreeElement(); - return selectedElement instanceof NavigatableErrorTreeElement ? (NavigatableErrorTreeElement)selectedElement : null; - } - - public @Nullable ErrorTreeElement getSelectedErrorTreeElement() { - final ErrorTreeNodeDescriptor treeNodeDescriptor = getSelectedNodeDescriptor(); - return treeNodeDescriptor == null? null : treeNodeDescriptor.getElement(); - } - - public @Nullable ErrorTreeNodeDescriptor getSelectedNodeDescriptor() { - List descriptors = getSelectedNodeDescriptors(); - return descriptors.size() == 1 ? descriptors.get(0) : null; - } - - public @Nullable VirtualFile getSelectedFile() { - final ErrorTreeNodeDescriptor descriptor = getSelectedNodeDescriptor(); - ErrorTreeElement element = descriptor != null? descriptor.getElement() : null; - if (element != null && !(element instanceof GroupingElement)) { - NodeDescriptor parent = descriptor.getParentDescriptor(); - if (parent instanceof ErrorTreeNodeDescriptor) { - element = ((ErrorTreeNodeDescriptor)parent).getElement(); + val selectedFile: VirtualFile? + get() { + val descriptor = selectedNodeDescriptor + var element = descriptor?.element + if (element != null && element !is GroupingElement) { + val parent = descriptor!!.parentDescriptor + if (parent is ErrorTreeNodeDescriptor) { + element = parent.element + } } + return if (element is GroupingElement) element.file else null } - return element instanceof GroupingElement? ((GroupingElement)element).getFile() : null; - } - private List getSelectedNodeDescriptors() { - TreePath[] paths = myIsDisposed ? null : myTree.getSelectionPaths(); - if (paths == null) { - return Collections.emptyList(); - } - List result = new ArrayList<>(); - for (TreePath path : paths) { - DefaultMutableTreeNode lastPathNode = (DefaultMutableTreeNode)path.getLastPathComponent(); - Object userObject = lastPathNode.getUserObject(); - if (userObject instanceof ErrorTreeNodeDescriptor) { - result.add((ErrorTreeNodeDescriptor)userObject); + private val selectedNodeDescriptors: List + get() { + val paths = (if (isDisposed) null else myTree.selectionPaths) ?: return emptyList() + val result = ArrayList() + for (path in paths) { + val lastPathNode = path.lastPathComponent as DefaultMutableTreeNode + val userObject = lastPathNode.userObject + if (userObject is ErrorTreeNodeDescriptor) { + result.add(userObject) + } } + return result } - return result; - } - private void navigateToSource(final boolean focusEditor) { - NavigatableErrorTreeElement element = getSelectedNavigatableElement(); - if (element == null) { - return; - } - final Navigatable navigatable = element.getNavigatable(); + private fun navigateToSource() { + val element = selectedNavigatableElement ?: return + val navigatable = element.navigatable if (navigatable.canNavigate()) { - navigatable.navigate(focusEditor); + navigatable.navigate(false) } } - public static String getQualifiedName(final VirtualFile file) { - return file.getPresentableUrl(); - } - - private void popupInvoked(Component component, int x, int y) { - final TreePath path = myTree.getLeadSelectionPath(); - if (path == null) { - return; + private fun popupInvoked(component: Component, x: Int, y: Int) { + if (myTree.leadSelectionPath == null) { + return } - DefaultActionGroup group = new DefaultActionGroup(); - if (getData(CommonDataKeys.NAVIGATABLE.getName()) != null) { - group.add(ActionManager.getInstance().getAction(IdeActions.ACTION_EDIT_SOURCE)); + + val group = DefaultActionGroup() + if (getData(CommonDataKeys.NAVIGATABLE.name) != null) { + group.add(ActionManager.getInstance().getAction(IdeActions.ACTION_EDIT_SOURCE)) } - group.add(ActionManager.getInstance().getAction(IdeActions.ACTION_COPY)); - group.add(myAutoScrollToSourceHandler.createToggleAction()); - addExtraPopupMenuActions(group); - group.addSeparator(); - group.add(CommonActionsManager.getInstance().createExpandAllAction(myTreeExpander, this)); - group.add(CommonActionsManager.getInstance().createCollapseAllAction(myTreeExpander, this)); - group.addSeparator(); - group.add(new ExportToTextFileToolbarAction(myExporterToTextFile)); - - ActionPopupMenu menu = ActionManager.getInstance().createActionPopupMenu(ActionPlaces.COMPILER_MESSAGES_POPUP, group); - menu.getComponent().show(component, x, y); + group.add(ActionManager.getInstance().getAction(IdeActions.ACTION_COPY)) + group.add(autoScrollToSourceHandler.createToggleAction()) + addExtraPopupMenuActions(group) + group.addSeparator() + group.add(CommonActionsManager.getInstance().createExpandAllAction(treeExpander, this)) + group.add(CommonActionsManager.getInstance().createCollapseAllAction(treeExpander, this)) + group.addSeparator() + group.add(ExportToTextFileToolbarAction(exporterToTextFile)) + val menu = ActionManager.getInstance().createActionPopupMenu(ActionPlaces.COMPILER_MESSAGES_POPUP, group) + menu.component.show(component, x, y) } - protected void addExtraPopupMenuActions(DefaultActionGroup group) { + protected open fun addExtraPopupMenuActions(group: DefaultActionGroup) { } - public void setProcessController(ProcessController controller) { - myProcessController = controller; + fun setProcessController(controller: ProcessController?) { + processController = controller } - public void stopProcess() { - myProcessController.stopProcess(); + fun stopProcess() { + processController!!.stopProcess() } - public boolean canControlProcess() { - return myProcessController != null; + fun canControlProcess(): Boolean { + return processController != null } - public boolean isProcessStopped() { - return myProcessController.isProcessStopped(); - } + val isProcessStopped: Boolean + get() = processController!!.isProcessStopped - public void close() { - MessageView messageView = MessageView.getInstance(myProject); - Content content = messageView.getContentManager().getContent(this); - if (content != null) { - messageView.getContentManager().removeContent(content, true); - Disposer.dispose(this); + open fun close() { + val messageView = MessageView.getInstance(myProject) + messageView.contentManager.getContent(this)?.let { + messageView.contentManager.removeContent(it, true) + Disposer.dispose(this) } } - public void setProgress(final @NlsContexts.ProgressText String s, float fraction) { - myProgressText = s; - myFraction = fraction; - updateProgress(); + fun setProgress(s: @NlsContexts.ProgressText String?, fraction: Float) { + state.progressText = s + state.fraction = fraction + updateProgress() } - public void setProgressText(@NlsContexts.ProgressText String s) { - myProgressText = s; - updateProgress(); + fun setProgressText(s: @NlsContexts.ProgressText String?) { + state.progressText = s + updateProgress() } - public void setFraction(float fraction) { - myFraction = fraction; - updateProgress(); + fun setFraction(fraction: Float) { + state.fraction = fraction + updateProgress() } - public void clearProgressData() { - if (myProgressPanel != null) { - myProgressText = " "; - myFraction = 0.0f; - updateProgress(); - } + fun clearProgressData() { + state.clearProgress() + progressFlow.value = null } - private void updateProgress() { - if (myIsDisposed) { - return; + @ApiStatus.Internal + @ApiStatus.Experimental + fun updateProgress() { + progressFlow.value = state.progressText + } + + private fun initProgressPanel() { + if (progressPanel != null) { + return } - myUpdateAlarm.cancelAllRequests(); - myUpdateAlarm.addRequest(() -> { - initProgressPanel(); - - float fraction = myFraction; - String text = myProgressText; - if (fraction > 0.0f) { - myProgressLabel.setText((int)(fraction * 100 + 0.5) + "% " + text); - } - else { - myProgressLabel.setText(text); - } - }, 50, ModalityState.NON_MODAL); + val progressPanel = JPanel(GridLayout(1, 2)) + this.progressPanel = progressPanel + progressLabel = JLabel() + progressPanel.add(progressLabel) + //JLabel secondLabel = new JLabel(); + //myProgressPanel.add(secondLabel); + messagePanel.add(progressPanel, BorderLayout.SOUTH) + messagePanel.validate() } - private void initProgressPanel() { - if (myProgressPanel == null) { - myProgressPanel = new JPanel(new GridLayout(1, 2)); - myProgressLabel = new JLabel(); - myProgressPanel.add(myProgressLabel); - //JLabel secondLabel = new JLabel(); - //myProgressPanel.add(secondLabel); - myMessagePanel.add(myProgressPanel, BorderLayout.SOUTH); - myMessagePanel.validate(); + fun collapseAll() { + TreeUtil.collapseAll(myTree, 2) + } + + fun expandAll() { + val selectionPaths = myTree.selectionPaths + val leadSelectionPath = myTree.leadSelectionPath + var row = 0 + while (row < myTree.rowCount) { + myTree.expandRow(row) + row++ } - } - - public void collapseAll() { - TreeUtil.collapseAll(myTree, 2); - } - - public void expandAll() { - TreePath[] selectionPaths = myTree.getSelectionPaths(); - TreePath leadSelectionPath = myTree.getLeadSelectionPath(); - int row = 0; - while (row < myTree.getRowCount()) { - myTree.expandRow(row); - row++; - } - - if (selectionPaths != null) { + selectionPaths?.let { // restore selection - myTree.setSelectionPaths(selectionPaths); + myTree.selectionPaths = it } - if (leadSelectionPath != null) { + leadSelectionPath?.let { // scroll to lead selection path - myTree.scrollPathToVisible(leadSelectionPath); + myTree.scrollPathToVisible(it) } } - private JPanel createToolbarPanel(@Nullable Runnable rerunAction) { - DefaultActionGroup group = new DefaultActionGroup(); - AnAction closeMessageViewAction = new CloseTabToolbarAction() { - @Override - public void actionPerformed(@NotNull AnActionEvent e) { - close(); + private fun createToolbarPanel(rerunAction: Runnable?): JPanel { + val group = DefaultActionGroup() + val closeMessageViewAction: AnAction = object : CloseTabToolbarAction() { + override fun actionPerformed(e: AnActionEvent) { + close() } - }; - + } if (rerunAction != null) { - group.add(new RerunAction(rerunAction, closeMessageViewAction)); + group.add(RerunAction(rerunAction, closeMessageViewAction)) } - - group.add(new StopAction()); + group.add(StopAction()) if (canHideWarnings()) { - group.addSeparator(); - group.add(new ShowInfosAction()); - group.add(new ShowWarningsAction()); + group.addSeparator() + group.add(ShowInfosAction()) + group.add(ShowWarningsAction()) } - - fillRightToolbarGroup(group); + fillRightToolbarGroup(group) //if (myCreateExitAction) { // leftUpdateableActionGroup.add(closeMessageViewAction); @@ -587,217 +566,115 @@ public class NewErrorTreeViewPanel extends JPanel implements DataProvider, Occur //leftUpdateableActionGroup.add(new PreviousOccurenceToolbarAction(this)); //leftUpdateableActionGroup.add(new NextOccurenceToolbarAction(this)); //leftUpdateableActionGroup.add(new ExportToTextFileToolbarAction(myExporterToTextFile)); - - ActionManager actionManager = ActionManager.getInstance(); - myLeftToolbar = actionManager.createActionToolbar(ActionPlaces.COMPILER_MESSAGES_TOOLBAR, group, false); - myLeftToolbar.setTargetComponent(myMessagePanel); - return JBUI.Panels.simplePanel(myLeftToolbar.getComponent()); + val actionManager = ActionManager.getInstance() + leftToolbar = actionManager.createActionToolbar(ActionPlaces.COMPILER_MESSAGES_TOOLBAR, group, false) + leftToolbar!!.targetComponent = messagePanel + return JBUI.Panels.simplePanel(leftToolbar!!.component) } - protected void fillRightToolbarGroup(DefaultActionGroup group) { - + protected open fun fillRightToolbarGroup(group: DefaultActionGroup) { } - @Override - public OccurenceInfo goNextOccurence() { - return myOccurrenceNavigatorSupport.goNextOccurence(); - } + override fun goNextOccurence(): OccurenceNavigator.OccurenceInfo = occurrenceNavigatorSupport.goNextOccurence() - @Override - public OccurenceInfo goPreviousOccurence() { - return myOccurrenceNavigatorSupport.goPreviousOccurence(); - } + override fun goPreviousOccurence(): OccurenceNavigator.OccurenceInfo = occurrenceNavigatorSupport.goPreviousOccurence() - @Override - public boolean hasNextOccurence() { - return myOccurrenceNavigatorSupport.hasNextOccurence(); - } + override fun hasNextOccurence() = occurrenceNavigatorSupport.hasNextOccurence() - @Override - public boolean hasPreviousOccurence() { - return myOccurrenceNavigatorSupport.hasPreviousOccurence(); - } + override fun hasPreviousOccurence() = occurrenceNavigatorSupport.hasPreviousOccurence() - @Override - public @NotNull String getNextOccurenceActionName() { - return myOccurrenceNavigatorSupport.getNextOccurenceActionName(); - } + override fun getNextOccurenceActionName() = occurrenceNavigatorSupport.nextOccurenceActionName - @Override - public @NotNull String getPreviousOccurenceActionName() { - return myOccurrenceNavigatorSupport.getPreviousOccurenceActionName(); - } + override fun getPreviousOccurenceActionName() = occurrenceNavigatorSupport.previousOccurenceActionName - private class RerunAction extends DumbAwareAction { - private final Runnable myRerunAction; - private final AnAction myCloseAction; - - RerunAction(@NotNull Runnable rerunAction, @NotNull AnAction closeAction) { - super(IdeBundle.message("action.refresh"), null, AllIcons.Actions.Rerun); - myRerunAction = rerunAction; - myCloseAction = closeAction; + private inner class RerunAction(private val rerunAction: Runnable, private val closeAction: AnAction) + : DumbAwareAction(IdeBundle.message("action.refresh"), null, AllIcons.Actions.Rerun) { + override fun actionPerformed(e: AnActionEvent) { + closeAction.actionPerformed(e) + rerunAction.run() } - @Override - public void actionPerformed(@NotNull AnActionEvent e) { - myCloseAction.actionPerformed(e); - myRerunAction.run(); - } - - @Override - public void update(@NotNull AnActionEvent event) { - final Presentation presentation = event.getPresentation(); - presentation.setEnabled(canControlProcess() && isProcessStopped()); + override fun update(event: AnActionEvent) { + val presentation = event.presentation + presentation.isEnabled = canControlProcess() && isProcessStopped } } - private class StopAction extends DumbAwareAction { - StopAction() { - super(IdeBundle.messagePointer("action.stop"), AllIcons.Actions.Suspend); - } - - @Override - public void actionPerformed(@NotNull AnActionEvent e) { + private inner class StopAction : DumbAwareAction(IdeBundle.messagePointer("action.stop"), AllIcons.Actions.Suspend) { + override fun actionPerformed(e: AnActionEvent) { if (canControlProcess()) { - stopProcess(); + stopProcess() } - myLeftToolbar.updateActionsImmediately(); + leftToolbar!!.updateActionsImmediately() } - @Override - public void update(@NotNull AnActionEvent event) { - Presentation presentation = event.getPresentation(); - presentation.setEnabled(canControlProcess() && !isProcessStopped()); - presentation.setVisible(canControlProcess()); + override fun update(event: AnActionEvent) { + val presentation = event.presentation + presentation.isEnabled = canControlProcess() && !isProcessStopped + presentation.isVisible = canControlProcess() } } - protected boolean canHideWarnings() { - return true; - } + protected open fun canHideWarnings(): Boolean = true - private class ShowWarningsAction extends ToggleAction implements DumbAware { - ShowWarningsAction() { - super(IdeBundle.messagePointer("action.show.warnings"), AllIcons.General.ShowWarning); - } + private inner class ShowWarningsAction : ToggleAction(IdeBundle.messagePointer("action.show.warnings"), + AllIcons.General.ShowWarning), DumbAware { + override fun isSelected(event: AnActionEvent) = !isHideWarnings - @Override - public boolean isSelected(@NotNull AnActionEvent event) { - return !isHideWarnings(); - } - - @Override - public void setSelected(@NotNull AnActionEvent event, boolean showWarnings) { - final boolean hideWarnings = !showWarnings; - if (myConfiguration.isHideWarnings() != hideWarnings) { - myConfiguration.setHideWarnings(hideWarnings); - myStructureModel.invalidateAsync(); + override fun setSelected(event: AnActionEvent, showWarnings: Boolean) { + val hideWarnings = !showWarnings + if (configuration.isHideWarnings != hideWarnings) { + configuration.isHideWarnings = hideWarnings + structureModel.invalidateAsync() } } } - private class ShowInfosAction extends ToggleAction implements DumbAware { - ShowInfosAction() { - super(IdeBundle.messagePointer("action.show.infos"), AllIcons.General.ShowInfos); - } + private inner class ShowInfosAction : ToggleAction(IdeBundle.messagePointer("action.show.infos"), + AllIcons.General.ShowInfos), DumbAware { + override fun isSelected(event: AnActionEvent) = !isHideInfos - @Override - public boolean isSelected(@NotNull AnActionEvent event) { - return !isHideInfos(); - } - - @Override - public void setSelected(@NotNull AnActionEvent event, boolean showInfos) { - final boolean hideInfos = !showInfos; - if (myConfiguration.isHideInfoMessages() != hideInfos) { - myConfiguration.setHideInfoMessages(hideInfos); - myStructureModel.invalidateAsync(); + override fun setSelected(event: AnActionEvent, showInfos: Boolean) { + val hideInfos = !showInfos + if (configuration.isHideInfoMessages != hideInfos) { + configuration.isHideInfoMessages = hideInfos + structureModel.invalidateAsync() } } } - public boolean isHideWarnings() { - return myConfiguration.isHideWarnings(); + val isHideWarnings: Boolean + get() = configuration.isHideWarnings + + val isHideInfos: Boolean + get() = configuration.isHideInfoMessages + + override fun getGroupChildrenData(groupName: String): List = errorViewStructure.getGroupChildrenData(groupName) + + override fun removeGroup(name: String) { + errorViewStructure.removeGroup(name) } - public boolean isHideInfos() { - return myConfiguration.isHideInfoMessages(); + override fun addFixedHotfixGroup(text: String, children: List) { + errorViewStructure.addFixedHotfixGroup(text, children) } - private class MyTreeExpander implements TreeExpander { - @Override - public void expandAll() { - NewErrorTreeViewPanel.this.expandAll(); - } - - @Override - public boolean canExpand() { - return true; - } - - @Override - public void collapseAll() { - NewErrorTreeViewPanel.this.collapseAll(); - } - - @Override - public boolean canCollapse() { - return true; - } + override fun addHotfixGroup(hotfixData: HotfixData, children: List) { + errorViewStructure.addHotfixGroup(hotfixData, children, this) } - private static class MyOccurrenceNavigatorSupport extends OccurenceNavigatorSupport { - MyOccurrenceNavigatorSupport(final Tree tree) { - super(tree); - } + override fun reload() { + structureModel.invalidateAsync() + } +} - @Override - protected Navigatable createDescriptorForNode(@NotNull DefaultMutableTreeNode node) { - Object userObject = node.getUserObject(); - if (!(userObject instanceof ErrorTreeNodeDescriptor)) { - return null; - } - final ErrorTreeNodeDescriptor descriptor = (ErrorTreeNodeDescriptor)userObject; - final ErrorTreeElement element = descriptor.getElement(); - if (element instanceof NavigatableErrorTreeElement) { - return ((NavigatableErrorTreeElement)element).getNavigatable(); - } - return null; - } - - @Override - public @NotNull String getNextOccurenceActionName() { - return IdeBundle.message("action.next.message"); - } - - @Override - public @NotNull String getPreviousOccurenceActionName() { - return IdeBundle.message("action.previous.message"); - } +private class MyOccurrenceNavigatorSupport(tree: Tree) : OccurenceNavigatorSupport(tree) { + override fun createDescriptorForNode(node: DefaultMutableTreeNode): Navigatable? { + val userObject = node.userObject as? ErrorTreeNodeDescriptor + return (userObject?.element as? NavigatableErrorTreeElement)?.navigatable } - @Override - public List getGroupChildrenData(final String groupName) { - return myErrorViewStructure.getGroupChildrenData(groupName); - } + override fun getNextOccurenceActionName() = IdeBundle.message("action.next.message") - @Override - public void removeGroup(final String name) { - myErrorViewStructure.removeGroup(name); - } - - @Override - public void addFixedHotfixGroup(String text, List children) { - myErrorViewStructure.addFixedHotfixGroup(text, children); - } - - @Override - public void addHotfixGroup(HotfixData hotfixData, List children) { - myErrorViewStructure.addHotfixGroup(hotfixData, children, this); - } - - @Override - public void reload() { - myStructureModel.invalidateAsync(); - } + override fun getPreviousOccurenceActionName() = IdeBundle.message("action.previous.message") } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ide/errorTreeView/SimpleMessageElement.java b/platform/platform-impl/src/com/intellij/ide/errorTreeView/SimpleMessageElement.java index 907386f7c389..296a7fa9d000 100644 --- a/platform/platform-impl/src/com/intellij/ide/errorTreeView/SimpleMessageElement.java +++ b/platform/platform-impl/src/com/intellij/ide/errorTreeView/SimpleMessageElement.java @@ -1,4 +1,4 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.ide.errorTreeView; import org.jetbrains.annotations.NotNull; @@ -6,7 +6,7 @@ import org.jetbrains.annotations.NotNull; /** * @author Eugene Zhuravlev */ -public class SimpleMessageElement extends ErrorTreeElement{ +public final class SimpleMessageElement extends ErrorTreeElement{ private final String[] myMessage; private final Object myData; diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowIcon.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowIcon.kt index a1d8dfdecda0..23a5ed253d0e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowIcon.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowIcon.kt @@ -1,63 +1,33 @@ // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.openapi.wm.impl; +package com.intellij.openapi.wm.impl -import com.intellij.openapi.util.IconLoader; -import com.intellij.openapi.util.ScalableIcon; -import com.intellij.ui.RetrievableIcon; -import com.intellij.ui.icons.MenuBarIconProvider; -import com.intellij.util.IconUtil; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import java.awt.*; +import com.intellij.openapi.util.IconLoader +import com.intellij.openapi.util.ScalableIcon +import com.intellij.ui.RetrievableIcon +import com.intellij.ui.icons.MenuBarIconProvider +import com.intellij.util.IconUtil +import java.awt.Component +import java.awt.Graphics +import javax.swing.Icon /** * @author Konstantin Bulenkov */ -public final class ToolWindowIcon implements RetrievableIcon, MenuBarIconProvider, ScalableIcon { - @NotNull - private final Icon myIcon; - private final String myToolWindowId; +internal class ToolWindowIcon(private val icon: Icon, + private val toolWindowId: String) : RetrievableIcon, MenuBarIconProvider, ScalableIcon { + override fun retrieveIcon() = icon - ToolWindowIcon(@NotNull Icon icon, @NotNull String toolWindowId) { - myIcon = icon; - myToolWindowId = toolWindowId; + override fun getMenuBarIcon(isDark: Boolean) = ToolWindowIcon(IconLoader.getMenuBarIcon(icon, isDark), toolWindowId) + + override fun paintIcon(c: Component, g: Graphics, x: Int, y: Int) { + icon.paintIcon(c, g, x, y) } - @Override - @NotNull - public Icon retrieveIcon() { - return myIcon; - } + override fun getIconWidth() = icon.iconWidth - @NotNull - @Override - public Icon getMenuBarIcon(boolean isDark) { - return new ToolWindowIcon(IconLoader.getMenuBarIcon(myIcon, isDark), myToolWindowId); - } + override fun getIconHeight() = icon.iconHeight - @Override - public void paintIcon(Component c, Graphics g, int x, int y) { - myIcon.paintIcon(c, g, x, y); - } + override fun getScale() = if (icon is ScalableIcon) icon.scale else 1f - @Override - public int getIconWidth() { - return myIcon.getIconWidth(); - } - - @Override - public int getIconHeight() { - return myIcon.getIconHeight(); - } - - @Override - public float getScale() { - return myIcon instanceof ScalableIcon ? ((ScalableIcon)myIcon).getScale() : 1f; - } - - @Override - public @NotNull Icon scale(float scaleFactor) { - return new ToolWindowIcon(IconUtil.scaleOrLoadCustomVersion(myIcon, scaleFactor), myToolWindowId); - } -} + override fun scale(scaleFactor: Float) = ToolWindowIcon(IconUtil.scaleOrLoadCustomVersion(icon, scaleFactor), toolWindowId) +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.kt index 7a7eda3310d7..e7a7b52cab13 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.kt @@ -416,7 +416,7 @@ internal class ToolWindowImpl(val toolWindowManager: ToolWindowManagerImpl, } else { if (pendingContentManagerListeners == null) { - pendingContentManagerListeners = arrayListOf() + pendingContentManagerListeners = mutableListOf() } pendingContentManagerListeners!!.add(listener) } @@ -432,8 +432,10 @@ internal class ToolWindowImpl(val toolWindowManager: ToolWindowManagerImpl, override fun setIcon(newIcon: Icon) { EDT.assertIsEdt() - doSetIcon(newIcon) - toolWindowManager.toolWindowPropertyChanged(this, ToolWindowProperty.ICON) + if (newIcon !== icon?.retrieveIcon()) { + doSetIcon(newIcon) + toolWindowManager.toolWindowPropertyChanged(this, ToolWindowProperty.ICON) + } } internal fun doSetIcon(newIcon: Icon) { @@ -805,7 +807,7 @@ private class ToolWindowFocusWatcher(private val toolWindow: ToolWindowImpl, com } private fun setBackgroundRecursively(component: Component, bg: Color) { - UIUtil.forEachComponentInHierarchy(component, Consumer { c: Component -> + UIUtil.forEachComponentInHierarchy(component, Consumer { c -> if (c !is ActionButton && c !is Divider) { c.background = bg } diff --git a/platform/platform-impl/src/com/intellij/ui/tree/StructureTreeModel.java b/platform/platform-impl/src/com/intellij/ui/tree/StructureTreeModel.java index 0218fa995497..d6fc622685bc 100644 --- a/platform/platform-impl/src/com/intellij/ui/tree/StructureTreeModel.java +++ b/platform/platform-impl/src/com/intellij/ui/tree/StructureTreeModel.java @@ -111,7 +111,7 @@ public class StructureTreeModel */ private @NotNull CompletableFuture onValidThread(@NotNull Function function) { CompletableFuture future = new CompletableFuture<>(); - invoker.invoke(() -> { + invoker.compute(() -> { if (!disposed) { Result result = function.apply(structure); if (result != null) { @@ -121,6 +121,7 @@ public class StructureTreeModel if (!future.isDone()) { future.completeExceptionally(AsyncPromise.CANCELED); } + return null; }).onError(future::completeExceptionally); return future; } diff --git a/platform/platform-impl/src/com/intellij/util/concurrency/Invoker.java b/platform/platform-impl/src/com/intellij/util/concurrency/Invoker.java index 4d711b86b88e..5cec5e2f38ac 100644 --- a/platform/platform-impl/src/com/intellij/util/concurrency/Invoker.java +++ b/platform/platform-impl/src/com/intellij/util/concurrency/Invoker.java @@ -1,4 +1,4 @@ -// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.util.concurrency; import com.intellij.openapi.Disposable; @@ -76,8 +76,7 @@ public abstract class Invoker implements Disposable { * @param task a task to execute on the valid thread * @return an object to control task processing */ - @NotNull - public final CancellablePromise compute(@NotNull Supplier task) { + public final @NotNull CancellablePromise compute(@NotNull Supplier task) { return promise(new Task<>(task)); } @@ -90,21 +89,8 @@ public abstract class Invoker implements Disposable { * @param task a task to execute asynchronously on the valid thread * @return an object to control task processing */ - @NotNull - public final CancellablePromise computeLater(@NotNull Supplier task) { - return computeLater(task, 0); - } - - /** - * Computes the specified task on the valid thread after the specified delay. - * - * @param task a task to execute asynchronously on the valid thread - * @param delay milliseconds for the initial delay - * @return an object to control task processing - */ - @NotNull - public final CancellablePromise computeLater(@NotNull Supplier task, int delay) { - return promise(new Task<>(task), delay); + public final @NotNull CancellablePromise computeLater(@NotNull Supplier task) { + return promise(new Task<>(task), 0); } /** @@ -114,8 +100,7 @@ public abstract class Invoker implements Disposable { * @param task a task to execute on the valid thread * @return an object to control task processing */ - @NotNull - public final CancellablePromise invoke(@NotNull Runnable task) { + public final @NotNull CancellablePromise invoke(@NotNull Runnable task) { return compute(new Wrapper(task)); } @@ -128,8 +113,7 @@ public abstract class Invoker implements Disposable { * @param task a task to execute asynchronously on the valid thread * @return an object to control task processing */ - @NotNull - public final CancellablePromise invokeLater(@NotNull Runnable task) { + public final @NotNull CancellablePromise invokeLater(@NotNull Runnable task) { return invokeLater(task, 0); } @@ -140,9 +124,8 @@ public abstract class Invoker implements Disposable { * @param delay milliseconds for the initial delay * @return an object to control task processing */ - @NotNull - public final CancellablePromise invokeLater(@NotNull Runnable task, int delay) { - return computeLater(new Wrapper(task), delay); + public final @NotNull CancellablePromise invokeLater(@NotNull Runnable task, int delay) { + return promise(new Task<>(new Wrapper(task)), delay); } /** @@ -153,9 +136,8 @@ public abstract class Invoker implements Disposable { * @return an object to control task processing * @deprecated use {@link #invoke(Runnable)} or {@link #compute(Supplier)} instead */ - @NotNull @Deprecated(forRemoval = true) - public final CancellablePromise runOrInvokeLater(@NotNull Runnable task) { + public final @NotNull CancellablePromise runOrInvokeLater(@NotNull Runnable task) { return invoke(task); } @@ -241,9 +223,10 @@ public abstract class Invoker implements Disposable { * @param task a task to execute on the valid thread * @return an object to control task processing */ - @NotNull - private CancellablePromise promise(@NotNull Task task) { - if (!isValidThread()) return promise(task, 0); + private @NotNull CancellablePromise promise(@NotNull Task task) { + if (!isValidThread()) { + return promise(task, 0); + } count.incrementAndGet(); invokeSafely(task, 0); return task.promise; @@ -256,10 +239,13 @@ public abstract class Invoker implements Disposable { * @param delay milliseconds for the initial delay * @return an object to control task processing */ - @NotNull - private CancellablePromise promise(@NotNull Task task, int delay) { - if (delay < 0) throw new IllegalArgumentException("delay must be non-negative: " + delay); - if (task.canInvoke(disposed)) offerSafely(task, 0, delay); + private @NotNull CancellablePromise promise(@NotNull Task task, int delay) { + if (delay < 0) { + throw new IllegalArgumentException("delay must be non-negative: " + delay); + } + if (task.canInvoke(disposed)) { + offerSafely(task, 0, delay); + } return task.promise; } @@ -349,8 +335,7 @@ public abstract class Invoker implements Disposable { } - @NotNull - private ProgressIndicatorBase indicator(@NotNull AsyncPromise promise) { + private @NotNull ProgressIndicatorBase indicator(@NotNull AsyncPromise promise) { ProgressIndicatorBase indicator = indicators.get(promise); if (indicator == null) { indicator = new ProgressIndicatorBase(true, false); @@ -500,28 +485,23 @@ public abstract class Invoker implements Disposable { } - @NotNull - public static Invoker forEventDispatchThread(@NotNull Disposable parent) { + public static @NotNull Invoker forEventDispatchThread(@NotNull Disposable parent) { return new EDT(parent); } - @NotNull - public static Invoker forBackgroundPoolWithReadAction(@NotNull Disposable parent) { + public static @NotNull Invoker forBackgroundPoolWithReadAction(@NotNull Disposable parent) { return new Background(parent, ThreeState.YES, 8); } - @NotNull - public static Invoker forBackgroundPoolWithoutReadAction(@NotNull Disposable parent) { + public static @NotNull Invoker forBackgroundPoolWithoutReadAction(@NotNull Disposable parent) { return new Background(parent, ThreeState.NO, 8); } - @NotNull - public static Invoker forBackgroundThreadWithReadAction(@NotNull Disposable parent) { + public static @NotNull Invoker forBackgroundThreadWithReadAction(@NotNull Disposable parent) { return new Background(parent, ThreeState.YES, 1); } - @NotNull - public static Invoker forBackgroundThreadWithoutReadAction(@NotNull Disposable parent) { + public static @NotNull Invoker forBackgroundThreadWithoutReadAction(@NotNull Disposable parent) { return new Background(parent, ThreeState.NO, 1); } } diff --git a/platform/service-container/src/com/intellij/serviceContainer/ComponentManagerImpl.kt b/platform/service-container/src/com/intellij/serviceContainer/ComponentManagerImpl.kt index 0e296ea6c3a2..31685e4744f2 100644 --- a/platform/service-container/src/com/intellij/serviceContainer/ComponentManagerImpl.kt +++ b/platform/service-container/src/com/intellij/serviceContainer/ComponentManagerImpl.kt @@ -7,10 +7,7 @@ import com.intellij.ide.plugins.* import com.intellij.ide.plugins.cl.PluginAwareClassLoader import com.intellij.idea.Main import com.intellij.openapi.Disposable -import com.intellij.openapi.application.AccessToken -import com.intellij.openapi.application.Application -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.application.invokeAndWaitIfNeeded +import com.intellij.openapi.application.* import com.intellij.openapi.components.* import com.intellij.openapi.components.ServiceDescriptor.PreloadMode import com.intellij.openapi.components.impl.stores.IComponentStore @@ -1473,9 +1470,4 @@ private inline fun executeRegisterTask(mainPluginDescriptor: IdeaPluginDescripto crossinline task: (IdeaPluginDescriptorImpl) -> Unit) { task(mainPluginDescriptor) executeRegisterTaskForOldContent(mainPluginDescriptor, task) -} - -private fun createSupervisorCoroutineScope(parentScope: CoroutineScope): CoroutineScope { - val parentContext = parentScope.coroutineContext - return CoroutineScope(parentContext + SupervisorJob(parent = parentContext.job)) } \ No newline at end of file