mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-02-04 23:39:07 +07:00
IJPL-158073 Introduce DataSink.lazyValue
(cherry picked from commit cb3a4d617192638c05ec24feca1128e1625931da) IJ-CR-158811 GitOrigin-RevId: 345df15b9e296be66a6a540af058058bcf982b4a
This commit is contained in:
committed by
intellij-monorepo-bot
parent
0ff4a1342d
commit
1189cb9281
@@ -57,13 +57,16 @@ f:com.intellij.openapi.actionSystem.DataKey
|
||||
- f:is(java.lang.String):Z
|
||||
f:com.intellij.openapi.actionSystem.DataKey$Companion
|
||||
- f:create(java.lang.String):com.intellij.openapi.actionSystem.DataKey
|
||||
com.intellij.openapi.actionSystem.DataMap
|
||||
- a:get(com.intellij.openapi.actionSystem.DataKey):java.lang.Object
|
||||
com.intellij.openapi.actionSystem.DataProvider
|
||||
- a:getData(java.lang.String):java.lang.Object
|
||||
com.intellij.openapi.actionSystem.DataSink
|
||||
- sf:Companion:com.intellij.openapi.actionSystem.DataSink$Companion
|
||||
- a:dataSnapshot(com.intellij.openapi.actionSystem.DataSnapshotProvider):V
|
||||
- a:lazy(com.intellij.openapi.actionSystem.DataKey,kotlin.jvm.functions.Function0):V
|
||||
- lazy(com.intellij.openapi.actionSystem.DataKey,kotlin.jvm.functions.Function0):V
|
||||
- a:lazyNull(com.intellij.openapi.actionSystem.DataKey):V
|
||||
- a:lazyValue(com.intellij.openapi.actionSystem.DataKey,kotlin.jvm.functions.Function1):V
|
||||
- a:set(com.intellij.openapi.actionSystem.DataKey,java.lang.Object):V
|
||||
- a:setNull(com.intellij.openapi.actionSystem.DataKey):V
|
||||
- a:uiDataSnapshot(com.intellij.openapi.actionSystem.DataProvider):V
|
||||
@@ -74,7 +77,7 @@ f:com.intellij.openapi.actionSystem.DataSink$Companion
|
||||
- f:uiDataSnapshot(com.intellij.openapi.actionSystem.DataSink,com.intellij.openapi.actionSystem.DataProvider):V
|
||||
- f:uiDataSnapshot(com.intellij.openapi.actionSystem.DataSink,java.lang.Object):V
|
||||
com.intellij.openapi.actionSystem.DataSnapshot
|
||||
- a:get(com.intellij.openapi.actionSystem.DataKey):java.lang.Object
|
||||
- com.intellij.openapi.actionSystem.DataMap
|
||||
com.intellij.openapi.actionSystem.DataSnapshotProvider
|
||||
- a:dataSnapshot(com.intellij.openapi.actionSystem.DataSink):V
|
||||
com.intellij.openapi.actionSystem.EdtNoGetDataProvider
|
||||
|
||||
@@ -5,7 +5,7 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.Component;
|
||||
|
||||
/**
|
||||
* Allows an action to retrieve information about the context in which it was invoked.
|
||||
|
||||
@@ -52,15 +52,21 @@ fun interface UiDataProvider {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data map representation.
|
||||
*/
|
||||
@ApiStatus.NonExtendable
|
||||
interface DataMap {
|
||||
|
||||
operator fun <T : Any> get(key: DataKey<T>): T?
|
||||
}
|
||||
|
||||
/**
|
||||
* A data snapshot representation.
|
||||
* [UiDataRule] operates on it.
|
||||
*/
|
||||
@ApiStatus.NonExtendable
|
||||
interface DataSnapshot {
|
||||
|
||||
operator fun <T : Any> get(key: DataKey<T>): T?
|
||||
}
|
||||
interface DataSnapshot: DataMap
|
||||
|
||||
/**
|
||||
* A non-EDT version of [UiDataProvider].
|
||||
@@ -152,7 +158,14 @@ interface DataSink {
|
||||
/**
|
||||
* Put the [PlatformCoreDataKeys.BGT_DATA_PROVIDER] lambda in the sink
|
||||
*/
|
||||
fun <T : Any> lazy(key: DataKey<T>, data: () -> T?)
|
||||
fun <T : Any> lazy(key: DataKey<T>, data: () -> T?) {
|
||||
lazyValue(key) { data() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the [PlatformCoreDataKeys.BGT_DATA_PROVIDER] lambda in the sink
|
||||
*/
|
||||
fun <T : Any> lazyValue(key: DataKey<T>, data: (provider: DataMap) -> T?)
|
||||
|
||||
/**
|
||||
* Put the [com.intellij.openapi.actionSystem.CustomizedDataContext.EXPLICIT_NULL] value in the sink
|
||||
|
||||
@@ -33,15 +33,22 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.concurrency.AsyncPromise;
|
||||
import org.jetbrains.concurrency.Promise;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import java.awt.Component;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.awt.Window;
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.openapi.actionSystem.PlatformCoreDataKeys.BGT_DATA_PROVIDER;
|
||||
|
||||
/** @noinspection removal*/
|
||||
public class DataManagerImpl extends DataManager {
|
||||
private static final Logger LOG = Logger.getInstance(DataManagerImpl.class);
|
||||
|
||||
private static final ThreadLocal<int[]> ourGetDataLevel = ThreadLocal.withInitial(() -> new int[1]);
|
||||
private static class ThreadState { int depth; Set<String> ids; }
|
||||
private static final ThreadLocal<ThreadState> ourGetDataLevel = ThreadLocal.withInitial(() -> new ThreadState());
|
||||
|
||||
private final Map<Pair<String, GetDataRuleType>, GetDataRule> myRulesCache = ConcurrentFactoryMap.createMap(o -> getDataRule(o.first, o.second));
|
||||
|
||||
@@ -71,60 +78,56 @@ public class DataManagerImpl extends DataManager {
|
||||
public @Nullable Object getDataFromProviderAndRules(@NotNull String dataId,
|
||||
@Nullable GetDataRuleType ruleType,
|
||||
@NotNull DataProvider provider) {
|
||||
return getDataFromProviderAndRulesInner(dataId, ruleType, null, provider);
|
||||
return getDataFromProviderAndRulesInner(dataId, ruleType, provider);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public @Nullable Object getDataFromRules(@NotNull String dataId,
|
||||
@NotNull GetDataRuleType ruleType,
|
||||
@NotNull DataProvider provider) {
|
||||
return getDataFromRulesInner(dataId, ruleType, null, provider);
|
||||
return getDataFromRulesInner(dataId, ruleType, provider);
|
||||
}
|
||||
|
||||
private @Nullable Object getDataFromProviderAndRulesInner(@NotNull String dataId,
|
||||
@Nullable GetDataRuleType ruleType,
|
||||
@Nullable Set<String> alreadyComputedIds,
|
||||
@NotNull DataProvider provider) {
|
||||
ProgressManager.checkCanceled();
|
||||
if (alreadyComputedIds != null && alreadyComputedIds.contains(dataId)) {
|
||||
ThreadState state = ourGetDataLevel.get();
|
||||
if (state.ids != null && state.ids.contains(dataId)) {
|
||||
return null;
|
||||
}
|
||||
int[] depth = ourGetDataLevel.get();
|
||||
state.depth++;
|
||||
try {
|
||||
depth[0]++;
|
||||
Object data = getDataFromProviderInner(dataId, provider);
|
||||
Object data = getDataFromProviderInner(dataId, provider, null);
|
||||
if (data != null) {
|
||||
return data;
|
||||
}
|
||||
return ruleType == null ? null : getDataFromRulesInner(dataId, ruleType, alreadyComputedIds, provider);
|
||||
return ruleType == null ? null : getDataFromRulesInner(dataId, ruleType, provider);
|
||||
}
|
||||
finally {
|
||||
depth[0]--;
|
||||
if (alreadyComputedIds != null) alreadyComputedIds.remove(dataId);
|
||||
state.depth--;
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable Object getDataFromRulesInner(@NotNull String dataId,
|
||||
@NotNull GetDataRuleType ruleType,
|
||||
@Nullable Set<String> alreadyComputedIds,
|
||||
@NotNull DataProvider provider) {
|
||||
GetDataRule rule = myRulesCache.get(Pair.create(dataId, ruleType));
|
||||
if (rule == null) return null;
|
||||
return getDataFromRuleInner(rule, dataId, ruleType, alreadyComputedIds, provider);
|
||||
return getDataFromRuleInner(rule, dataId, ruleType, provider);
|
||||
}
|
||||
|
||||
private @Nullable Object getDataFromRuleInner(@NotNull GetDataRule rule,
|
||||
@NotNull String dataId,
|
||||
@NotNull GetDataRuleType ruleType,
|
||||
@Nullable Set<String> alreadyComputedIds,
|
||||
@NotNull DataProvider provider) {
|
||||
int[] depth = ourGetDataLevel.get();
|
||||
ThreadState state = ourGetDataLevel.get();
|
||||
if (state.ids == null || state.depth == 0) state.ids = new HashSet<>();
|
||||
state.depth++;
|
||||
try {
|
||||
depth[0]++;
|
||||
Set<String> ids = alreadyComputedIds == null ? new HashSet<>() : alreadyComputedIds;
|
||||
ids.add(dataId);
|
||||
state.ids.add(dataId);
|
||||
Object data = rule.getData(id -> {
|
||||
Object o = getDataFromProviderAndRulesInner(id, ruleType, ids, provider);
|
||||
Object o = getDataFromProviderAndRulesInner(id, ruleType, provider);
|
||||
return o == CustomizedDataContext.EXPLICIT_NULL ? null : o;
|
||||
});
|
||||
return data == null ? null :
|
||||
@@ -132,7 +135,8 @@ public class DataManagerImpl extends DataManager {
|
||||
DataValidators.validOrNull(data, dataId, rule);
|
||||
}
|
||||
finally {
|
||||
depth[0]--;
|
||||
state.depth--;
|
||||
state.ids.remove(dataId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,19 +196,20 @@ public class DataManagerImpl extends DataManager {
|
||||
|
||||
private static @Nullable GetDataRule getDataRuleInner(@NotNull String dataId, @NotNull GetDataRuleType ruleType) {
|
||||
String uninjectedId = InjectedDataKeys.uninjectedId(dataId);
|
||||
GetDataRule slowRule = ruleType == GetDataRuleType.PROVIDER &&
|
||||
!PlatformCoreDataKeys.BGT_DATA_PROVIDER.is(dataId) ?
|
||||
dataProvider -> getSlowData(dataId, dataProvider) : null;
|
||||
boolean noSlowRule = ruleType != GetDataRuleType.PROVIDER || BGT_DATA_PROVIDER.is(dataId);
|
||||
List<GetDataRule> rules1 = rulesForKey(dataId, ruleType);
|
||||
List<GetDataRule> rules2 = uninjectedId == null ? null : rulesForKey(uninjectedId, ruleType);
|
||||
if (rules1 == null && rules2 == null) return slowRule;
|
||||
if (rules1 == null && rules2 == null && noSlowRule) return null;
|
||||
return dataProvider -> {
|
||||
Object data = slowRule == null ? null : slowRule.getData(dataProvider);
|
||||
data = data != null ? data : rules1 == null ? null : getRulesData(dataId, rules1, dataProvider);
|
||||
data = data != null ? data : rules2 == null ? null : getRulesData(dataId, rules2, id -> {
|
||||
DataProvider bgtProvider = noSlowRule ? null : BGT_DATA_PROVIDER.getData(dataProvider);
|
||||
DataProvider injectedProvider = uninjectedId == null ? null : id -> {
|
||||
String injectedId = InjectedDataKeys.injectedId(id);
|
||||
return injectedId != null ? dataProvider.getData(injectedId) : null;
|
||||
});
|
||||
};
|
||||
Object data = getDataFromProviderInner(dataId, bgtProvider, dataProvider);
|
||||
data = data != null ? data : uninjectedId == null ? null : getDataFromProviderInner(uninjectedId, bgtProvider, injectedProvider);
|
||||
data = data != null ? data : rules1 == null ? null : getRulesData(dataId, rules1, dataProvider);
|
||||
data = data != null ? data : rules2 == null ? null : getRulesData(uninjectedId, rules2, injectedProvider);
|
||||
return data;
|
||||
};
|
||||
}
|
||||
@@ -239,19 +244,17 @@ public class DataManagerImpl extends DataManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static @Nullable Object getSlowData(@NotNull String dataId, @NotNull DataProvider dataProvider) {
|
||||
DataProvider bgtProvider = PlatformCoreDataKeys.BGT_DATA_PROVIDER.getData(dataProvider);
|
||||
if (bgtProvider != null) {
|
||||
Object data = getDataFromProviderInner(dataId, bgtProvider);
|
||||
if (data != null) return data;
|
||||
private static @Nullable Object getDataFromProviderInner(@NotNull String dataId,
|
||||
@Nullable DataProvider provider,
|
||||
@Nullable DataProvider outerProvider) {
|
||||
if (provider == null) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static @Nullable Object getDataFromProviderInner(@NotNull String dataId, @NotNull DataProvider provider) {
|
||||
if (!(provider instanceof CompositeDataProvider)) {
|
||||
else if (!(provider instanceof CompositeDataProvider composite)) {
|
||||
try {
|
||||
Object data = provider.getData(dataId);
|
||||
Object data = provider instanceof ParametrizedDataProvider o
|
||||
? (outerProvider == null ? null : o.getData(dataId, outerProvider))
|
||||
: provider.getData(dataId);
|
||||
if (data != null) {
|
||||
return data == CustomizedDataContext.EXPLICIT_NULL ? data :
|
||||
DataValidators.validOrNull(data, dataId, provider);
|
||||
@@ -261,8 +264,8 @@ public class DataManagerImpl extends DataManager {
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (DataProvider p : ((CompositeDataProvider)provider).getDataProviders()) {
|
||||
Object data = getDataFromProviderInner(dataId, p);
|
||||
for (DataProvider p : composite.getDataProviders()) {
|
||||
Object data = getDataFromProviderInner(dataId, p, outerProvider);
|
||||
if (data != null) return data;
|
||||
}
|
||||
}
|
||||
@@ -272,7 +275,7 @@ public class DataManagerImpl extends DataManager {
|
||||
@Override
|
||||
public @NotNull DataContext getDataContext(Component component) {
|
||||
ThreadingAssertions.assertEventDispatchThread();
|
||||
if (ourGetDataLevel.get()[0] > 0) {
|
||||
if (ourGetDataLevel.get().depth > 0) {
|
||||
LOG.error("DataContext shall not be created and queried inside another getData() call.");
|
||||
}
|
||||
if (component instanceof DependentTransientComponent) {
|
||||
@@ -379,4 +382,9 @@ public class DataManagerImpl extends DataManager {
|
||||
|
||||
return editor;
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public interface ParametrizedDataProvider {
|
||||
Object getData(@NotNull String dataId, @NotNull DataProvider dataProvider);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,10 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
* <li><b>{@link GetDataRuleType#PROVIDER}</b> - a classic rule invoked on a single level data provider</li>
|
||||
* <li><b>{@link GetDataRuleType#CONTEXT}</b> - a classic rule invoked on the full context data provider</li>
|
||||
* </ul>
|
||||
*
|
||||
* @deprecated Use {@link com.intellij.openapi.actionSystem.DataSink#lazyValue} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@ApiStatus.Internal
|
||||
public enum GetDataRuleType {
|
||||
/**
|
||||
|
||||
@@ -11,7 +11,13 @@ import org.jetbrains.annotations.Nullable;
|
||||
* Provides data for given {@link com.intellij.openapi.actionSystem.DataKey}.
|
||||
* <p/>
|
||||
* Must be registered with {@code key} value matching {@code DataKey#getName()}.
|
||||
*
|
||||
* @deprecated Use {@link com.intellij.openapi.actionSystem.UiDataRule} instead.
|
||||
*
|
||||
* @see com.intellij.openapi.actionSystem.DataSink#lazy
|
||||
* @see com.intellij.openapi.actionSystem.DataSink#lazyValue
|
||||
*/
|
||||
@Deprecated
|
||||
public interface GetDataRule {
|
||||
ExtensionPointName<KeyedLazyInstance<GetDataRule>> EP_NAME = new ExtensionPointName<>("com.intellij.getDataRule");
|
||||
|
||||
|
||||
@@ -44,4 +44,7 @@ internal class TestDataSink : DataSink {
|
||||
override fun <T : Any> lazyNull(key: DataKey<T>) {
|
||||
set(key, null)
|
||||
}
|
||||
|
||||
override fun <T : Any> lazyValue(key: DataKey<T>, data: (DataMap) -> T?) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,6 +523,10 @@ private class MySink : DataSink {
|
||||
})
|
||||
}
|
||||
|
||||
override fun <T : Any> lazyValue(key: DataKey<T>, data: (DataMap) -> T?) {
|
||||
set(PlatformCoreDataKeys.BGT_DATA_PROVIDER, MyLazyValue(key, data))
|
||||
}
|
||||
|
||||
override fun uiDataSnapshot(provider: UiDataProvider) {
|
||||
val prev = source
|
||||
source = provider
|
||||
@@ -566,12 +570,25 @@ private class MySink : DataSink {
|
||||
|
||||
private class MyLazy<T>(val key: DataKey<T>, val supplier: () -> T?) : DataProvider, DataValidators.SourceWrapper {
|
||||
override fun getData(dataId: String): Any? {
|
||||
return if (key.`is`(dataId)) supplier.invoke() else null
|
||||
if (!key.`is`(dataId)) return null
|
||||
return supplier.invoke()
|
||||
}
|
||||
override fun unwrapSource(): Any = supplier
|
||||
override fun toString(): String = "Lazy(${key.name})"
|
||||
}
|
||||
|
||||
private class MyLazyValue<T>(val key: DataKey<T>, val supplier: (DataMap) -> T?) : DataProvider, DataManagerImpl.ParametrizedDataProvider, DataValidators.SourceWrapper {
|
||||
override fun getData(dataId: String, dataProvider: DataProvider): Any? {
|
||||
if (!key.`is`(dataId)) return null
|
||||
return supplier.invoke(object : DataMap {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : Any> get(key: DataKey<T>): T? = dataProvider.getData(key.name) as T?
|
||||
})
|
||||
}
|
||||
|
||||
override fun unwrapSource(): Any {
|
||||
return supplier
|
||||
}
|
||||
override fun getData(dataId: String): Any? = null
|
||||
override fun unwrapSource(): Any = supplier
|
||||
override fun toString(): String = "LazyValue(${key.name})"
|
||||
}
|
||||
|
||||
private fun hideEditor(component: Component?): Boolean {
|
||||
|
||||
Reference in New Issue
Block a user