mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Fixes IDEA-218532 Freezes in CodeStyle.getSettings
Code style settings are computed asynchronously on a background thread with a notification sent upon completion. GitOrigin-RevId: 8e82a1e540f1880961788703e42f7f1e21ad62a4
This commit is contained in:
committed by
intellij-monorepo-bot
parent
a191c2eae3
commit
08210fb4d2
@@ -11,6 +11,7 @@ import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.*;
|
||||
import com.intellij.psi.codeStyle.modifier.CodeStyleSettingsModifier;
|
||||
import com.intellij.psi.codeStyle.modifier.TransientCodeStyleSettings;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
@@ -70,6 +71,12 @@ public class CodeStyle {
|
||||
*/
|
||||
@NotNull
|
||||
public static CodeStyleSettings getSettings(@NotNull PsiFile file) {
|
||||
final Project project = file.getProject();
|
||||
CodeStyleSettings tempSettings = CodeStyleSettingsManager.getInstance(project).getTemporarySettings();
|
||||
if (tempSettings != null) {
|
||||
return tempSettings;
|
||||
}
|
||||
|
||||
for (FileCodeStyleProvider provider : FileCodeStyleProvider.EP_NAME.getIterable()) {
|
||||
CodeStyleSettings fileSettings = provider.getSettings(file);
|
||||
if (fileSettings != null) {
|
||||
@@ -78,9 +85,9 @@ public class CodeStyle {
|
||||
}
|
||||
|
||||
if (!file.isPhysical()) {
|
||||
return getSettings(file.getProject());
|
||||
return getSettings(project);
|
||||
}
|
||||
return CodeStyleCachingUtil.getCachedCodeStyle(file);
|
||||
return CachedValuesManager.getCachedValue(file, CodeStyleCachedValueProvider.getInstance(file));
|
||||
}
|
||||
|
||||
|
||||
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
// 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.application.options;
|
||||
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.SimpleModificationTracker;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.codeStyle.modifier.CodeStyleSettingsModifier;
|
||||
import com.intellij.psi.codeStyle.modifier.TransientCodeStyleSettings;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
class CodeStyleCachedValueProvider implements CachedValueProvider<CodeStyleSettings> {
|
||||
private final static Logger LOG = Logger.getInstance(CodeStyleCachedValueProvider.class);
|
||||
|
||||
private final static Key<CodeStyleCachedValueProvider> PROVIDER_KEY = Key.create("code.style.cached.value.provider");
|
||||
|
||||
private final @NotNull PsiFile myFile;
|
||||
private final @NotNull AsyncComputation myComputation;
|
||||
|
||||
CodeStyleCachedValueProvider(@NotNull PsiFile file) {
|
||||
myFile = file;
|
||||
myComputation = new AsyncComputation();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Result<CodeStyleSettings> compute() {
|
||||
CodeStyleSettings settings = myComputation.getCurrResult();
|
||||
logCached(myFile, settings);
|
||||
return new Result<>(settings, getDependencies(settings, myComputation));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
Object[] getDependencies(@NotNull CodeStyleSettings settings, @NotNull AsyncComputation computation) {
|
||||
List<Object> dependencies = new ArrayList<>();
|
||||
if (settings instanceof TransientCodeStyleSettings) {
|
||||
dependencies.addAll(((TransientCodeStyleSettings)settings).getDependencies());
|
||||
}
|
||||
else {
|
||||
dependencies.add(settings.getModificationTracker());
|
||||
}
|
||||
dependencies.add(computation.getTracker());
|
||||
return ArrayUtil.toObjectArray(dependencies);
|
||||
}
|
||||
|
||||
static synchronized CodeStyleCachedValueProvider getInstance(@NotNull PsiFile file) {
|
||||
CodeStyleCachedValueProvider instance = file.getUserData(PROVIDER_KEY);
|
||||
if (instance == null) {
|
||||
instance = new CodeStyleCachedValueProvider(file);
|
||||
file.putUserData(PROVIDER_KEY, instance);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private void notifyCachedValueComputed(@NotNull PsiFile file) {
|
||||
final Application application = ApplicationManager.getApplication();
|
||||
if (!application.isUnitTestMode()) {
|
||||
application.invokeLater(() -> {
|
||||
final CodeStyleSettingsManager settingsManager = CodeStyleSettingsManager.getInstance(file.getProject());
|
||||
settingsManager.fireCodeStyleSettingsChanged(file);
|
||||
myComputation.reset();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static void logCached(@NotNull PsiFile file, @NotNull CodeStyleSettings settings) {
|
||||
LOG.debug(String.format(
|
||||
"File: %s (%s), cached: %s, tracker: %d", file.getName(), Integer.toHexString(file.hashCode()), settings,
|
||||
settings.getModificationTracker().getModificationCount()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Always contains some result which can be obtained by {@code getCurrResult()} method. Listeners are notified after
|
||||
* the computation is finished and {@code getCurrResult()} contains a stable computed value.
|
||||
*/
|
||||
private class AsyncComputation {
|
||||
private final AtomicBoolean myIsActive = new AtomicBoolean();
|
||||
private volatile @NotNull CodeStyleSettings myCurrResult;
|
||||
private final @NotNull CodeStyleSettingsManager mySettingsManager;
|
||||
private final SimpleModificationTracker myTracker = new SimpleModificationTracker();
|
||||
|
||||
private AsyncComputation() {
|
||||
mySettingsManager = CodeStyleSettingsManager.getInstance(myFile.getProject());
|
||||
//noinspection deprecation
|
||||
myCurrResult = mySettingsManager.getCurrentSettings();
|
||||
}
|
||||
|
||||
private void start() {
|
||||
final Application application = ApplicationManager.getApplication();
|
||||
if (!application.isUnitTestMode()) {
|
||||
application.executeOnPooledThread(() -> computeSettings());
|
||||
}
|
||||
else {
|
||||
computeSettings();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void computeSettings() {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Computation started for " + myFile.getName());
|
||||
}
|
||||
@SuppressWarnings("deprecation")
|
||||
CodeStyleSettings currSettings = mySettingsManager.getCurrentSettings();
|
||||
if (currSettings != mySettingsManager.getTemporarySettings()) {
|
||||
TransientCodeStyleSettings modifiableSettings = new TransientCodeStyleSettings(myFile, currSettings);
|
||||
for (CodeStyleSettingsModifier modifier : CodeStyleSettingsModifier.EP_NAME.getExtensionList()) {
|
||||
if (modifier.modifySettings(modifiableSettings, myFile)) {
|
||||
LOG.debug("Modifier: " + modifier.getClass().getName());
|
||||
modifiableSettings.setModifier(modifier);
|
||||
currSettings = modifiableSettings;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
myCurrResult = currSettings;
|
||||
myTracker.incModificationCount();
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Computation ended for " + myFile.getName());
|
||||
}
|
||||
notifyCachedValueComputed(myFile);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CodeStyleSettings getCurrResult() {
|
||||
if (myIsActive.compareAndSet(false, true)) {
|
||||
start();
|
||||
}
|
||||
return myCurrResult;
|
||||
}
|
||||
|
||||
private SimpleModificationTracker getTracker() {
|
||||
return myTracker;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
myIsActive.set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +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.application.options;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.codeStyle.modifier.CodeStyleSettingsModifier;
|
||||
import com.intellij.psi.codeStyle.modifier.TransientCodeStyleSettings;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
class CodeStyleCachingUtil {
|
||||
private final static Logger LOG = Logger.getInstance(CodeStyleCachingUtil.class);
|
||||
|
||||
@NotNull
|
||||
static CodeStyleSettings getCachedCodeStyle(@NotNull PsiFile file) {
|
||||
CachedCodeStyleHolder cachedCodeStyleHolder = CachedValuesManager.getCachedValue(file, () -> createHolder(file).getCachedResult());
|
||||
return cachedCodeStyleHolder.getCachedSettings();
|
||||
}
|
||||
|
||||
private static CachedCodeStyleHolder createHolder(@NotNull PsiFile file) {
|
||||
CachedCodeStyleHolder holder = new CachedCodeStyleHolder();
|
||||
holder.compute(file);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
logCached(file, holder);
|
||||
}
|
||||
return holder;
|
||||
}
|
||||
|
||||
static class CachedCodeStyleHolder {
|
||||
private @NotNull CodeStyleSettings myCachedSettings = CodeStyle.getDefaultSettings();
|
||||
|
||||
private void compute(@NotNull PsiFile file) {
|
||||
final CodeStyleSettingsManager settingsManager = CodeStyleSettingsManager.getInstance(file.getProject());
|
||||
@SuppressWarnings("deprecation")
|
||||
CodeStyleSettings currSettings = myCachedSettings = settingsManager.getCurrentSettings();
|
||||
if (currSettings != settingsManager.getTemporarySettings()) {
|
||||
TransientCodeStyleSettings modifiableSettings = new TransientCodeStyleSettings(file, currSettings);
|
||||
for (CodeStyleSettingsModifier modifier : CodeStyleSettingsModifier.EP_NAME.getExtensionList()) {
|
||||
if (modifier.modifySettings(modifiableSettings, file)) {
|
||||
LOG.debug("Modifier: " + modifier.getClass().getName());
|
||||
modifiableSettings.setModifier(modifier);
|
||||
currSettings = modifiableSettings;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
myCachedSettings = currSettings;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
Object[] getDependencies() {
|
||||
return myCachedSettings instanceof TransientCodeStyleSettings ?
|
||||
((TransientCodeStyleSettings)myCachedSettings).getDependencies().toArray() :
|
||||
new Object[]{myCachedSettings.getModificationTracker()};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
CodeStyleSettings getCachedSettings() {
|
||||
return myCachedSettings;
|
||||
}
|
||||
|
||||
CachedValueProvider.Result<CachedCodeStyleHolder> getCachedResult() {
|
||||
return new CachedValueProvider.Result<>(this, this.getDependencies());
|
||||
}
|
||||
}
|
||||
|
||||
private static void logCached(@NotNull PsiFile file, @NotNull CachedCodeStyleHolder holder) {
|
||||
CodeStyleSettings settings = holder.getCachedSettings();
|
||||
LOG.debug(String.format(
|
||||
"File: %s (%s), cached: %s, tracker: %d", file.getName(), Integer.toHexString(file.hashCode()), settings, settings.getModificationTracker().getModificationCount()));
|
||||
}
|
||||
}
|
||||
@@ -148,12 +148,10 @@ public class CodeStyleSettingsManager implements PersistentStateComponent<Elemen
|
||||
* @see #dropTemporarySettings()
|
||||
*/
|
||||
public void setTemporarySettings(@NotNull CodeStyleSettings settings) {
|
||||
updateSettingsTracker();
|
||||
myTemporarySettings = settings;
|
||||
}
|
||||
|
||||
public void dropTemporarySettings() {
|
||||
updateSettingsTracker();
|
||||
myTemporarySettings = null;
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -60,6 +60,7 @@ public class FileCodeStyleProviderTest extends UsefulTestCase {
|
||||
|
||||
public void testFileCodeStyleProvider() {
|
||||
PsiFile file = myFixture.configureByText("a.java", "class Foo {}");
|
||||
CodeStyle.dropTemporarySettings(file.getProject());
|
||||
CodeStyleSettings settings = CodeStyle.getSettings(file);
|
||||
assertSame(myTestSettings, settings);
|
||||
}
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ class EditorConfigFileHierarchyServiceImpl(
|
||||
|
||||
private fun updateHandlers(project: Project) {
|
||||
updateQueue.queue(Update.create("editorconfig hierarchy update") {
|
||||
CodeStyleSettingsManager.getInstance(project).fireCodeStyleSettingsChanged(null)
|
||||
CodeStyleSettingsManager.getInstance(project).notifyCodeStyleSettingsChanged()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user