IJPL-158493 Introduce ProjectFileNodeUpdaterInvoker

To reuse ProjectFileNodeUpdater for the new coroutine-based
Project View, we need to remove its direct dependency on the legacy
Invoker. Introduce a new abstraction layer, including only
the methods that are really needed.

Because the existing implementation relies on the invoker
as the parent Disposable, we must implement it in the new
interface as well, and ensure that our invoker is disposed
along with the delegate.

To remove the dependency in AsyncProjectViewSupport,
remove the invoke() call around roots.forEach. It's a safe thing to do
because the ProjectFileNodeUpdater itself only ever invokes
updateStructure in the same invoker, so that wrapping
was effectively a no-op.

GitOrigin-RevId: dd239b1330a2d8ef84f09e1dc5e3a49d79d8414c
This commit is contained in:
Sergei Tachenov
2024-09-13 17:27:32 +00:00
committed by intellij-monorepo-bot
parent 2beb8da5c2
commit 8ee289751b
4 changed files with 48 additions and 2 deletions
@@ -73,7 +73,7 @@ public final class AsyncProjectViewSupport {
}
List<VirtualFile> roots = collector.get();
LOG.debug("found ", roots.size(), " roots in ", System.currentTimeMillis() - time, "ms");
myStructureTreeModel.getInvoker().invoke(() -> roots.forEach(root -> updateByFile(root, true)));
roots.forEach(root -> updateByFile(root, true));
}
}
};
@@ -29,12 +29,16 @@ import static com.intellij.psi.util.PsiUtilCore.getVirtualFile;
public abstract class ProjectFileNodeUpdater {
private static final Logger LOG = Logger.getInstance(ProjectFileNodeUpdater.class);
private final Ref<Set<VirtualFile>> reference = new Ref<>();
private final Invoker invoker;
private final ProjectFileNodeUpdaterInvoker invoker;
private volatile boolean root;
private volatile long time;
private volatile int size;
public ProjectFileNodeUpdater(@NotNull Project project, @NotNull Invoker invoker) {
this(project, new ProjectFileNodeUpdaterLegacyInvoker(invoker));
}
private ProjectFileNodeUpdater(@NotNull Project project, @NotNull ProjectFileNodeUpdaterInvoker invoker) {
this.invoker = invoker;
MessageBusConnection connection = project.getMessageBus().connect(invoker);
connection.subscribe(ModuleRootListener.TOPIC, new ModuleRootListener() {
@@ -0,0 +1,13 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.ui.tree.project;
import com.intellij.openapi.Disposable;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.concurrency.Promise;
@ApiStatus.Internal
public interface ProjectFileNodeUpdaterInvoker extends Disposable {
Promise<?> invoke(@NotNull Runnable runnable);
void invokeLater(@NotNull Runnable runnable, int delay);
}
@@ -0,0 +1,29 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.ui.tree.project;
import com.intellij.openapi.util.Disposer;
import com.intellij.util.concurrency.Invoker;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.concurrency.Promise;
class ProjectFileNodeUpdaterLegacyInvoker implements ProjectFileNodeUpdaterInvoker {
private final @NotNull Invoker myInvoker;
ProjectFileNodeUpdaterLegacyInvoker(@NotNull Invoker invoker) {
myInvoker = invoker;
Disposer.register(invoker, this);
}
@Override
public Promise<?> invoke(@NotNull Runnable runnable) {
return myInvoker.invoke(runnable);
}
@Override
public void invokeLater(@NotNull Runnable runnable, int delay) {
myInvoker.invokeLater(runnable, delay);
}
@Override
public void dispose() { }
}