mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
CPP-10639 Saving folding state triggers lazy blocks reparsing from EDT
Cancels storing of folding state by timeout on EDT. The problem comes from smart pointers, that initiate lazy block parsing. It's is hard in C++. Here is temporal solution util the platform start collecting the folding state in background. (cherry picked from commit edf15a5)
This commit is contained in:
+37
-32
@@ -30,9 +30,11 @@ import com.intellij.openapi.editor.FoldRegion;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.impl.text.CodeFoldingState;
|
||||
import com.intellij.openapi.progress.util.ProgressWithTimeoutInDispatch;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -204,7 +206,7 @@ class DocumentFoldingInfo implements JDOMExternalizable, CodeFoldingState {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeExternal(Element element) throws WriteExternalException {
|
||||
public void writeExternal(final Element element) throws WriteExternalException {
|
||||
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
|
||||
|
||||
if (myPsiElements.isEmpty() && myRangeMarkers.isEmpty() && mySerializedElements.isEmpty()){
|
||||
@@ -212,39 +214,42 @@ class DocumentFoldingInfo implements JDOMExternalizable, CodeFoldingState {
|
||||
}
|
||||
|
||||
if (mySerializedElements.isEmpty()) {
|
||||
for (SmartPsiElementPointer<PsiElement> ptr : myPsiElements) {
|
||||
PsiElement psiElement = ptr.getElement();
|
||||
if (psiElement == null || !psiElement.isValid()) {
|
||||
continue;
|
||||
}
|
||||
FoldingInfo fi = psiElement.getUserData(FOLDING_INFO_KEY);
|
||||
boolean state = fi != null && fi.expanded;
|
||||
String signature = FoldingPolicy.getSignature(psiElement);
|
||||
if (signature == null) {
|
||||
continue;
|
||||
}
|
||||
ProgressWithTimeoutInDispatch.execInDispatchWithTimeout(() -> {
|
||||
for (SmartPsiElementPointer<PsiElement> ptr : myPsiElements) {
|
||||
PsiElement psiElement = ptr.getElement();
|
||||
if (psiElement == null || !psiElement.isValid()) {
|
||||
continue;
|
||||
}
|
||||
FoldingInfo fi = psiElement.getUserData(FOLDING_INFO_KEY);
|
||||
boolean state = fi != null && fi.expanded;
|
||||
String signature = FoldingPolicy.getSignature(psiElement);
|
||||
if (signature == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PsiFile containingFile = psiElement.getContainingFile();
|
||||
PsiElement restoredElement = FoldingPolicy.restoreBySignature(containingFile, signature);
|
||||
if (!psiElement.equals(restoredElement)) {
|
||||
StringBuilder trace = new StringBuilder();
|
||||
PsiElement restoredAgain = FoldingPolicy.restoreBySignature(containingFile, signature, trace);
|
||||
LOG.error("element: " + psiElement + "(" + psiElement.getText()
|
||||
+ "); restoredElement: " + restoredElement
|
||||
+ "; signature: '" + signature
|
||||
+ "'; file: " + containingFile
|
||||
+ "; injected: " + InjectedLanguageManager.getInstance(myProject).isInjectedFragment(containingFile)
|
||||
+ "; languages: " + containingFile.getViewProvider().getLanguages()
|
||||
+ "; restored again: " + restoredAgain +
|
||||
"; restore produces same results: " + (restoredAgain == restoredElement)
|
||||
+ "; trace:\n" + trace);
|
||||
}
|
||||
PsiFile containingFile = psiElement.getContainingFile();
|
||||
PsiElement restoredElement = FoldingPolicy.restoreBySignature(containingFile, signature);
|
||||
if (!psiElement.equals(restoredElement)) {
|
||||
StringBuilder trace = new StringBuilder();
|
||||
PsiElement restoredAgain = FoldingPolicy.restoreBySignature(containingFile, signature, trace);
|
||||
LOG.error("element: " + psiElement + "(" + psiElement.getText()
|
||||
+ "); restoredElement: " + restoredElement
|
||||
+ "; signature: '" + signature
|
||||
+ "'; file: " + containingFile
|
||||
+ "; injected: " + InjectedLanguageManager.getInstance(myProject).isInjectedFragment(containingFile)
|
||||
+ "; languages: " + containingFile.getViewProvider().getLanguages()
|
||||
+ "; restored again: " + restoredAgain +
|
||||
"; restore produces same results: " + (restoredAgain == restoredElement)
|
||||
+ "; trace:\n" + trace);
|
||||
}
|
||||
|
||||
Element e = new Element(ELEMENT_TAG);
|
||||
e.setAttribute(SIGNATURE_ATT, signature);
|
||||
e.setAttribute(EXPANDED_ATT, Boolean.toString(state));
|
||||
element.addContent(e);
|
||||
}
|
||||
Element e = new Element(ELEMENT_TAG);
|
||||
e.setAttribute(SIGNATURE_ATT, signature);
|
||||
e.setAttribute(EXPANDED_ATT, Boolean.toString(state));
|
||||
element.addContent(e);
|
||||
}
|
||||
return Void.TYPE;
|
||||
}, Registry.get("save.folding.state.timeout").asInteger());
|
||||
}
|
||||
else {
|
||||
// get back postponed state (before folding initialization)
|
||||
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.progress.util;
|
||||
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ProgressWithTimeoutInDispatch extends AbstractProgressIndicatorExBase implements PingProgress {
|
||||
private final long myTimeoutMs;
|
||||
private final long myStartTimeMs;
|
||||
|
||||
private ProgressWithTimeoutInDispatch(long timeoutMs) {
|
||||
super();
|
||||
myTimeoutMs = timeoutMs;
|
||||
myStartTimeMs = System.currentTimeMillis();
|
||||
setIndeterminate(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCanceled() {
|
||||
if (System.currentTimeMillis() - myStartTimeMs >= myTimeoutMs) {
|
||||
cancel();
|
||||
}
|
||||
return super.isCanceled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interact() {}
|
||||
|
||||
|
||||
/**
|
||||
* Cancels the <code>action</code> by the <code>ProcessCanceledException</code> exception
|
||||
* after <code>timeoutMs</code> ms on event dispatch thread.
|
||||
*
|
||||
* The <code>action</code> is not limited by any timeout if it is called on non-dispatch
|
||||
* thread, or <code>timeoutMs <= 0</code>, or the thread has progress indicator.
|
||||
*
|
||||
* @throws ProcessCanceledException
|
||||
*/
|
||||
@Nullable
|
||||
public static <T> T execInDispatchWithTimeout(@NotNull Computable<T> action, long timeoutMs) throws ProcessCanceledException {
|
||||
final Application application = ApplicationManager.getApplication();
|
||||
if (application.isDispatchThread()
|
||||
&& timeoutMs > 0
|
||||
&& ProgressManager.getInstance().getProgressIndicator() == null) {
|
||||
try {
|
||||
return ProgressManager.getInstance().runProcess(action, new ProgressWithTimeoutInDispatch(timeoutMs));
|
||||
}
|
||||
catch (ProcessCanceledException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return action.compute();
|
||||
}
|
||||
}
|
||||
@@ -1080,6 +1080,8 @@ welcome.screen.project.grouping.enabled.description=Allows to group recent proje
|
||||
|
||||
custom.folding.max.lookup.depth=50
|
||||
custom.folding.max.lookup.depth.description=Max lookup depth for custom folding comments in a PSI tree.
|
||||
save.folding.state.timeout=0
|
||||
save.folding.state.timeout.description=Timeout after which folding state saving is forcibly cancelled (0 means no time limit)
|
||||
|
||||
project.structure.add.tools.jar.to.new.jdk=false
|
||||
project.structure.add.tools.jar.to.new.jdk.description=Automatically add tools.jar to 'Classpath' when new JDK is created
|
||||
|
||||
Reference in New Issue
Block a user