mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Allow more than one folding range per AST node [r=kb]
This commit is contained in:
committed by
Roman Chernyatchik
parent
b5677bd343
commit
d85a64e20b
@@ -32,6 +32,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
public interface FoldingBuilder {
|
||||
/**
|
||||
* Builds the folding regions for the specified node in the AST tree and its children.
|
||||
* Note that you can have several folding regions for one AST node, i.e. several FoldingDescriptior with similar AST node.
|
||||
*
|
||||
* @param node the node for which folding is requested.
|
||||
* @param document the document for which folding is built. Can be used to retrieve line
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.psi.util.ParameterizedCachedValue;
|
||||
import com.intellij.psi.util.ParameterizedCachedValueProvider;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -86,7 +87,7 @@ public class FoldingUpdate {
|
||||
final Editor editor,
|
||||
final boolean applyDefaultState) {
|
||||
|
||||
final TreeMap<PsiElement, FoldingDescriptor> elementsToFoldMap = new TreeMap<PsiElement, FoldingDescriptor>(COMPARE_BY_OFFSET);
|
||||
final FoldingMap elementsToFoldMap = new FoldingMap();
|
||||
getFoldingsFor(file instanceof PsiCompiledElement ? (PsiFile)((PsiCompiledElement)file).getMirror() : file, document, elementsToFoldMap, quick);
|
||||
|
||||
final UpdateFoldRegionsOperation operation = new UpdateFoldRegionsOperation(project, editor, file, elementsToFoldMap, applyDefaultState, false);
|
||||
@@ -120,8 +121,7 @@ public class FoldingUpdate {
|
||||
List<DocumentWindow> injectedDocuments = InjectedLanguageUtil.getCachedInjectedDocuments(file);
|
||||
if (injectedDocuments.isEmpty()) return null;
|
||||
final List<EditorWindow> injectedEditors = new ArrayList<EditorWindow>();
|
||||
final List<PsiFile> injectedFiles = new ArrayList<PsiFile>();
|
||||
final List<Map<PsiElement, FoldingDescriptor>> maps = new ArrayList<Map<PsiElement, FoldingDescriptor>>();
|
||||
final List<FoldingMap> maps = new ArrayList<FoldingMap>();
|
||||
for (DocumentWindow injectedDocument : injectedDocuments) {
|
||||
PsiFile injectedFile = PsiDocumentManager.getInstance(project).getPsiFile(injectedDocument);
|
||||
if (injectedFile == null || !injectedFile.isValid() || !injectedDocument.isValid()) continue;
|
||||
@@ -129,8 +129,7 @@ public class FoldingUpdate {
|
||||
if (!(injectedEditor instanceof EditorWindow)) continue;
|
||||
|
||||
injectedEditors.add((EditorWindow)injectedEditor);
|
||||
injectedFiles.add(injectedFile);
|
||||
Map<PsiElement, FoldingDescriptor> map = new TreeMap<PsiElement, FoldingDescriptor>(COMPARE_BY_OFFSET);
|
||||
final FoldingMap map = new FoldingMap();
|
||||
maps.add(map);
|
||||
getFoldingsFor(injectedFile, injectedDocument, map, false);
|
||||
}
|
||||
@@ -141,8 +140,8 @@ public class FoldingUpdate {
|
||||
EditorWindow injectedEditor = injectedEditors.get(i);
|
||||
PsiFile injectedFile = injectedFiles.get(i);
|
||||
if (!injectedEditor.getDocument().isValid()) continue;
|
||||
Map<PsiElement, FoldingDescriptor> map = maps.get(i);
|
||||
UpdateFoldRegionsOperation op = new UpdateFoldRegionsOperation(project, injectedEditor, injectedFile, map, applyDefaultState, true);
|
||||
FoldingMap map = maps.get(i);
|
||||
UpdateFoldRegionsOperation op = new UpdateFoldRegionsOperation(project, injectedEditor, map, applyDefaultState, true);
|
||||
injectedEditor.getFoldingModel().runBatchFoldingOperationDoNotCollapseCaret(op);
|
||||
}
|
||||
|
||||
@@ -151,7 +150,10 @@ public class FoldingUpdate {
|
||||
};
|
||||
}
|
||||
|
||||
private static void getFoldingsFor(@NotNull PsiFile file, @NotNull Document document, @NotNull Map<PsiElement, FoldingDescriptor> elementsToFoldMap, boolean quick) {
|
||||
private static void getFoldingsFor(@NotNull PsiFile file,
|
||||
@NotNull Document document,
|
||||
@NotNull FoldingMap elementsToFoldMap,
|
||||
boolean quick) {
|
||||
final FileViewProvider viewProvider = file.getViewProvider();
|
||||
for (final Language language : viewProvider.getLanguages()) {
|
||||
final PsiFile psi = viewProvider.getPsi(language);
|
||||
@@ -167,10 +169,17 @@ public class FoldingUpdate {
|
||||
" and called on file " + psi +
|
||||
" is outside document range: " + docRange);
|
||||
}
|
||||
elementsToFoldMap.put(descriptor.getElement().getPsi(), descriptor);
|
||||
elementsToFoldMap.putValue(descriptor.getElement().getPsi(), descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class FoldingMap extends MultiMap<PsiElement, FoldingDescriptor>{
|
||||
@Override
|
||||
protected Map<PsiElement, Collection<FoldingDescriptor>> createMap() {
|
||||
return new TreeMap<PsiElement, Collection<FoldingDescriptor>>(COMPARE_BY_OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+51
-39
@@ -33,6 +33,7 @@ import com.intellij.psi.SmartPointerManager;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -43,20 +44,20 @@ import static com.intellij.util.containers.CollectionFactory.newTroveMap;
|
||||
* @author cdr
|
||||
*/
|
||||
class UpdateFoldRegionsOperation implements Runnable {
|
||||
|
||||
|
||||
static final Key<Boolean> ALLOW_FOLDING_ON_CARET_LINE_KEY = Key.create("AllowFoldingOnCaretLine.KEY");
|
||||
|
||||
|
||||
private final Project myProject;
|
||||
private final Editor myEditor;
|
||||
private final PsiFile myFile;
|
||||
private final boolean myApplyDefaultState;
|
||||
private final Map<PsiElement, FoldingDescriptor> myElementsToFoldMap;
|
||||
private final FoldingUpdate.FoldingMap myElementsToFoldMap;
|
||||
private final boolean myForInjected;
|
||||
|
||||
UpdateFoldRegionsOperation(@NotNull Project project,
|
||||
@NotNull Editor editor,
|
||||
@NotNull PsiFile file,
|
||||
@NotNull Map<PsiElement, FoldingDescriptor> elementsToFoldMap,
|
||||
@NotNull FoldingUpdate.FoldingMap elementsToFoldMap,
|
||||
boolean applyDefaultState,
|
||||
boolean forInjected) {
|
||||
myProject = project;
|
||||
@@ -79,7 +80,7 @@ class UpdateFoldRegionsOperation implements Runnable {
|
||||
List<FoldRegion> newRegions = addNewRegions(info, foldingModel, rangeToExpandStatusMap, shouldExpand, groupExpand);
|
||||
|
||||
applyExpandStatus(newRegions, shouldExpand, groupExpand);
|
||||
|
||||
|
||||
// Reset the key.
|
||||
myEditor.putUserData(ALLOW_FOLDING_ON_CARET_LINE_KEY, false);
|
||||
}
|
||||
@@ -102,19 +103,18 @@ class UpdateFoldRegionsOperation implements Runnable {
|
||||
Map<FoldingGroup, Boolean> groupExpand) {
|
||||
List<FoldRegion> newRegions = arrayList();
|
||||
SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(myProject);
|
||||
|
||||
for (final Map.Entry<PsiElement, FoldingDescriptor> entry : myElementsToFoldMap.entrySet()) {
|
||||
for (PsiElement element : myElementsToFoldMap.keySet()) {
|
||||
ProgressManager.checkCanceled();
|
||||
PsiElement element = entry.getKey();
|
||||
final FoldingDescriptor descriptor = entry.getValue();
|
||||
FoldingGroup group = descriptor.getGroup();
|
||||
TextRange range = descriptor.getRange();
|
||||
String placeholder = descriptor.getPlaceholderText();
|
||||
FoldRegion region = foldingModel.createFoldRegion(range.getStartOffset(), range.getEndOffset(),
|
||||
placeholder == null ? "..." : placeholder,
|
||||
group,
|
||||
descriptor.isNonExpandable());
|
||||
if (region == null) continue;
|
||||
final Collection<FoldingDescriptor> descriptors = myElementsToFoldMap.get(element);
|
||||
for (FoldingDescriptor descriptor : descriptors) {
|
||||
FoldingGroup group = descriptor.getGroup();
|
||||
TextRange range = descriptor.getRange();
|
||||
String placeholder = descriptor.getPlaceholderText();
|
||||
FoldRegion region = foldingModel.createFoldRegion(range.getStartOffset(), range.getEndOffset(),
|
||||
placeholder == null ? "..." : placeholder,
|
||||
group,
|
||||
descriptor.isNonExpandable());
|
||||
if (region == null) continue;
|
||||
|
||||
PsiElement psi = descriptor.getElement().getPsi();
|
||||
|
||||
@@ -126,15 +126,25 @@ class UpdateFoldRegionsOperation implements Runnable {
|
||||
info.addRegion(region, smartPointerManager.createSmartPsiElementPointer(psi, myFile));
|
||||
newRegions.add(region);
|
||||
|
||||
boolean expandStatus = !descriptor.isNonExpandable() && shouldExpandNewRegion(element, range, rangeToExpandStatusMap);
|
||||
if (group == null) {
|
||||
shouldExpand.put(region, expandStatus);
|
||||
}
|
||||
else {
|
||||
final Boolean alreadyExpanded = groupExpand.get(group);
|
||||
groupExpand.put(group, alreadyExpanded == null ? expandStatus : alreadyExpanded.booleanValue() || expandStatus);
|
||||
if (psi == null || !psi.isValid() || !foldingModel.addFoldRegion(region)) {
|
||||
region.dispose();
|
||||
continue;
|
||||
}
|
||||
|
||||
info.addRegion(region, smartPointerManager.createSmartPsiElementPointer(psi));
|
||||
newRegions.add(region);
|
||||
|
||||
boolean expandStatus = !descriptor.isNonExpandable() && shouldExpandNewRegion(element, range, rangeToExpandStatusMap);
|
||||
if (group == null) {
|
||||
shouldExpand.put(region, expandStatus);
|
||||
}
|
||||
else {
|
||||
final Boolean alreadyExpanded = groupExpand.get(group);
|
||||
groupExpand.put(group, alreadyExpanded == null ? expandStatus : alreadyExpanded.booleanValue() || expandStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newRegions;
|
||||
}
|
||||
|
||||
@@ -174,21 +184,23 @@ class UpdateFoldRegionsOperation implements Runnable {
|
||||
if (isInjected != myForInjected) continue;
|
||||
}
|
||||
if (element != null && myElementsToFoldMap.containsKey(element)) {
|
||||
final FoldingDescriptor descriptor = myElementsToFoldMap.get(element);
|
||||
TextRange range = descriptor.getRange();
|
||||
if (!region.isValid() ||
|
||||
region.getGroup() != null ||
|
||||
descriptor.getGroup() != null ||
|
||||
region.getStartOffset() != range.getStartOffset() ||
|
||||
region.getEndOffset() != range.getEndOffset() ||
|
||||
!region.getPlaceholderText().equals(descriptor.getPlaceholderText()) ||
|
||||
range.getLength() < 2
|
||||
) {
|
||||
rangeToExpandStatusMap.put(range, region.isExpanded());
|
||||
toRemove.add(region);
|
||||
}
|
||||
else {
|
||||
myElementsToFoldMap.remove(element);
|
||||
final Collection<FoldingDescriptor> descriptors = myElementsToFoldMap.get(element);
|
||||
for (FoldingDescriptor descriptor : descriptors) {
|
||||
TextRange range = descriptor.getRange();
|
||||
if (!region.isValid() ||
|
||||
region.getGroup() != null ||
|
||||
descriptor.getGroup() != null ||
|
||||
region.getStartOffset() != range.getStartOffset() ||
|
||||
region.getEndOffset() != range.getEndOffset() ||
|
||||
!region.getPlaceholderText().equals(descriptor.getPlaceholderText()) ||
|
||||
range.getLength() < 2
|
||||
) {
|
||||
rangeToExpandStatusMap.put(range, region.isExpanded());
|
||||
toRemove.add(region);
|
||||
}
|
||||
else {
|
||||
myElementsToFoldMap.remove(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (region.isValid() && info.isLightRegion(region)) {
|
||||
|
||||
Reference in New Issue
Block a user