[execution]: Implement temporal observables in execution module and get rid of ide dependency

GitOrigin-RevId: ba6aaf2be9308b856756a7d1e1687868c62e6e35
This commit is contained in:
Andrii Rublov
2024-02-22 01:30:36 +01:00
committed by intellij-monorepo-bot
parent 669de82138
commit 62574ecbba
3 changed files with 80 additions and 13 deletions

View File

@@ -10,7 +10,6 @@
<orderEntry type="library" name="kotlin-stdlib" level="project" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="intellij.platform.core" />
<orderEntry type="module" module-name="intellij.platform.ide" />
<orderEntry type="module" module-name="intellij.platform.ide.core" />
<orderEntry type="module" module-name="intellij.platform.ide.util.io" />
<orderEntry type="module" module-name="intellij.platform.util.ui" />

View File

@@ -0,0 +1,66 @@
// 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.execution.ui
import com.intellij.openapi.Disposable
import com.intellij.openapi.util.Disposer
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.ApiStatus.Experimental
import java.util.concurrent.atomic.AtomicReference
/**
* This is only a temporal API used to add reactivity possibilities into execution module until other options become available as a valid
* dependency.
* Do not use it. Use [com.intellij.openapi.observable.properties.ObservableProperty] instead.
*/
@ApiStatus.Internal
@Experimental
interface ReactiveProperty<T> {
fun getValue(): T
fun afterChange(parentDisposable: Disposable, listener: (T) -> Unit)
}
/**
* This is only a temporal API used to add reactivity possibilities into execution module until other options become available as a valid
* dependency.
* Do not use it. Use [com.intellij.openapi.observable.properties.ObservableProperty] instead.
*/
@ApiStatus.Internal
@Experimental
class MutableReactiveProperty<T>(initialValue: T) : ReactiveProperty<T> {
private val currentValue = AtomicReference<T>()
private val changeEvent = Event<T>()
override fun afterChange(parentDisposable: Disposable, listener: (T) -> Unit) {
val subscription = Disposable { changeEvent -= listener }
changeEvent += listener
Disposer.register(parentDisposable, subscription)
}
override fun getValue(): T = currentValue.get()
fun setValue(value: T) {
if (value == currentValue.get()) return
currentValue.set(value)
changeEvent.observers.forEach { it(value) }
}
}
private class Event<T> {
private val listenersList = mutableListOf<(T) -> Unit>()
val observers: List<(T) -> Unit> get() = listenersList
operator fun plusAssign(observer: (T) -> Unit) {
listenersList.add(observer)
}
operator fun minusAssign(observer: (T) -> Unit) {
listenersList.remove(observer)
}
operator fun invoke(value: T) {
for (observer in listenersList)
observer(value)
}
}

View File

@@ -9,8 +9,6 @@ import com.intellij.execution.process.ProcessHandler;
import com.intellij.ide.HelpIdProvider;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.observable.properties.AtomicProperty;
import com.intellij.openapi.observable.properties.ObservableProperty;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
@@ -32,8 +30,8 @@ public class RunContentDescriptor implements Disposable {
private ExecutionConsole myExecutionConsole;
private ProcessHandler myProcessHandler;
private JComponent myComponent;
private final AtomicProperty<@TabTitle String> myDisplayNameView = new AtomicProperty<>(null);
private final AtomicProperty<Icon> myIconView = new AtomicProperty<>(null);
private final MutableReactiveProperty<@TabTitle @Nullable String> myDisplayNameView = new MutableReactiveProperty<>(null);
private final MutableReactiveProperty<@Nullable Icon> myIconView = new MutableReactiveProperty<>(null);
private final String myHelpId;
private RunnerLayoutUi myRunnerLayoutUi = null;
private RunContentDescriptorReusePolicy myReusePolicy = RunContentDescriptorReusePolicy.DEFAULT;
@@ -71,8 +69,8 @@ public class RunContentDescriptor implements Disposable {
myExecutionConsole = executionConsole;
myProcessHandler = processHandler;
myComponent = component;
myDisplayNameView.set(displayName);
myIconView.set(icon);
myDisplayNameView.setValue(displayName);
myIconView.setValue(icon);
myHelpId = myExecutionConsole instanceof HelpIdProvider ? ((HelpIdProvider)myExecutionConsole).getHelpId() : null;
myActivationCallback = activationCallback;
if (myExecutionConsole != null) {
@@ -144,19 +142,21 @@ public class RunContentDescriptor implements Disposable {
*/
@Nullable
public Icon getIcon() {
return myIconView.get();
return myIconView.getValue();
}
/**
* Returns the reactive property for an icon to show in the Run or Debug toolwindow tab corresponding to this content.
* @return the icon property that can be observed for the most recent icon value.
*/
public ObservableProperty<Icon> getIconProperty() {
@ApiStatus.Experimental
public ReactiveProperty<Icon> getIconProperty() {
return myIconView;
}
@ApiStatus.Experimental
protected void setIcon(@Nullable Icon icon) {
myIconView.set(icon);
myIconView.setValue(icon);
}
@Nullable
@@ -186,19 +186,21 @@ public class RunContentDescriptor implements Disposable {
*/
@BuildEventsNls.Title
public String getDisplayName() {
return myDisplayNameView.get();
return myDisplayNameView.getValue();
}
/**
* Returns the reactive property for a title to show in the Run or Debug toolwindow tab corresponding to this content.
* @return the title property that can be observed for the most recent title value.
*/
public ObservableProperty<@Nullable @BuildEventsNls.Title String> getDisplayNameProperty() {
@ApiStatus.Experimental
public ReactiveProperty<@Nullable @BuildEventsNls.Title String> getDisplayNameProperty() {
return myDisplayNameView;
}
@ApiStatus.Experimental
protected void setDisplayName(@Nullable @TabTitle String displayName) {
myDisplayNameView.set(displayName);
myDisplayNameView.setValue(displayName);
}
public String getHelpId() {