@NotNull @Override public FoldingDescriptor[] buildFoldRegions(@NotNull PsiElement root, @NotNull Document document, boolean quick) { FoldingGroup group = FoldingGroup.newGroup("TYPO3Route"); List<FoldingDescriptor> descriptors = new ArrayList<>(); Collection<StringLiteralExpression> literalExpressions = PsiTreeUtil.findChildrenOfType(root, StringLiteralExpression.class); for (final StringLiteralExpression literalExpression : literalExpressions) { for (PsiReference reference : literalExpression.getReferences()) { if (reference instanceof RouteReference) { String value = literalExpression.getContents(); FoldingDescriptor descriptor = foldRouteReferenceString(reference, value, group); if (descriptor != null) { descriptors.add(descriptor); } } } } return descriptors.toArray(new FoldingDescriptor[descriptors.size()]); }
@Override public void run() { EditorFoldingInfo info = EditorFoldingInfo.get(myEditor); FoldingModelEx foldingModel = (FoldingModelEx)myEditor.getFoldingModel(); Map<TextRange,Boolean> rangeToExpandStatusMap = newTroveMap(); // FoldingUpdate caches instances of our object, so they must be immutable. FoldingUpdate.FoldingMap elementsToFold = new FoldingUpdate.FoldingMap(myElementsToFoldMap); removeInvalidRegions(info, foldingModel, elementsToFold, rangeToExpandStatusMap); Map<FoldRegion, Boolean> shouldExpand = newTroveMap(); Map<FoldingGroup, Boolean> groupExpand = newTroveMap(); List<FoldRegion> newRegions = addNewRegions(info, foldingModel, elementsToFold, rangeToExpandStatusMap, shouldExpand, groupExpand); applyExpandStatus(newRegions, shouldExpand, groupExpand); }
private static void collapseBlock(List<FoldingDescriptor> descriptors, PsiElement psi) { if (psi instanceof GrCodeBlock) { final int lineFeedCount = StringUtil.countChars(psi.getText(), '\n'); if (lineFeedCount <= 2) { final PsiElement lbrace = ((GrCodeBlock)psi).getLBrace(); final PsiElement rbrace = ((GrCodeBlock)psi).getRBrace(); if (lbrace != null && rbrace != null) { final PsiElement next = lbrace.getNextSibling(); final PsiElement prev = rbrace.getPrevSibling(); if (next != null && PsiImplUtil.isWhiteSpaceOrNls(next) && prev != null && PsiImplUtil.isWhiteSpaceOrNls(prev)) { final FoldingGroup group = FoldingGroup.newGroup("block_group"); descriptors.add(new NamedFoldingDescriptor(psi, lbrace.getTextRange().getStartOffset(), next.getTextRange().getEndOffset(), group, "{")); descriptors.add(new NamedFoldingDescriptor(psi, prev.getTextRange().getStartOffset(), rbrace.getTextRange().getEndOffset(), group, "}")); return; } } } } descriptors.add(new FoldingDescriptor(psi, psi.getTextRange())); }
@NotNull public FoldRegion getFirstRegion(@NotNull FoldingGroup group, FoldRegion child) { final List<FoldRegion> regions = getGroupedRegions(group); if (regions.isEmpty()) { final boolean inAll = Arrays.asList(getAllFoldRegions()).contains(child); throw new AssertionError("Folding group without children; the known child is in all: " + inAll); } FoldRegion main = regions.get(0); for (int i = 1; i < regions.size(); i++) { FoldRegion region = regions.get(i); if (main.getStartOffset() > region.getStartOffset()) { main = region; } } return main; }
@Override public boolean addFoldRegion(@NotNull final FoldRegion region) { assertIsDispatchThreadForEditor(); if (!isFoldingEnabled()) { return false; } if (!myIsBatchFoldingProcessing) { LOG.error("Fold regions must be added or removed inside batchFoldProcessing() only."); return false; } myFoldRegionsProcessed = true; if (myFoldTree.addRegion(region)) { final FoldingGroup group = region.getGroup(); if (group != null) { myGroups.putValue(group, region); } for (FoldingListener listener : myListeners) { listener.onFoldRegionStateChange(region); } return true; } return false; }
@Override public void removeFoldRegion(@NotNull final FoldRegion region) { assertIsDispatchThreadForEditor(); if (!myIsBatchFoldingProcessing) { LOG.error("Fold regions must be added or removed inside batchFoldProcessing() only."); } region.setExpanded(true); final FoldingGroup group = region.getGroup(); if (group != null) { myGroups.removeValue(group, region); } myFoldTree.removeRegion(region); myFoldRegionsProcessed = true; region.dispose(); }
private static void collapseBlock(List<FoldingDescriptor> descriptors, PsiElement psi) { if (psi instanceof GrCodeBlock) { final int lineFeedCount = StringUtil.countChars(psi.getText(), '\n'); if (lineFeedCount <= 2) { final PsiElement lbrace = ((GrCodeBlock)psi).getLBrace(); final PsiElement rbrace = ((GrCodeBlock)psi).getRBrace(); if (lbrace != null && rbrace != null) { final PsiElement next = lbrace.getNextSibling(); final PsiElement prev = rbrace.getPrevSibling(); if (next != null && WHITE_SPACES_SET.contains(next.getNode().getElementType()) && prev != null && WHITE_SPACES_SET.contains(prev.getNode().getElementType())) { final FoldingGroup group = FoldingGroup.newGroup("block_group"); descriptors.add(new NamedFoldingDescriptor(psi.getNode(), lbrace.getTextRange().getStartOffset(), next.getTextRange().getEndOffset(), group, "{")); descriptors.add(new NamedFoldingDescriptor(psi.getNode(), prev.getTextRange().getStartOffset(), rbrace.getTextRange().getEndOffset(), group, "}")); return; } } } } descriptors.add(new FoldingDescriptor(psi, psi.getTextRange())); }
UpdateFoldRegionsOperation(@Nonnull Project project, @Nonnull Editor editor, @Nonnull PsiFile file, @Nonnull List<FoldingUpdate.RegionInfo> elementsToFold, @Nonnull ApplyDefaultStateMode applyDefaultState, boolean keepCollapsedRegions, boolean forInjected) { myProject = project; myEditor = editor; myFile = file; myApplyDefaultState = applyDefaultState; myKeepCollapsedRegions = keepCollapsedRegions; myForInjected = forInjected; for (FoldingUpdate.RegionInfo regionInfo : elementsToFold) { myElementsToFoldMap.putValue(regionInfo.element, regionInfo); myRegionInfos.add(regionInfo); FoldingGroup group = regionInfo.descriptor.getGroup(); if (group != null) myGroupedRegionInfos.putValue(group, regionInfo); } }
@Override public void run() { EditorFoldingInfo info = EditorFoldingInfo.get(myEditor); FoldingModelEx foldingModel = (FoldingModelEx)myEditor.getFoldingModel(); Map<TextRange,Boolean> rangeToExpandStatusMap = new THashMap<>(); removeInvalidRegions(info, foldingModel, rangeToExpandStatusMap); Map<FoldRegion, Boolean> shouldExpand = new THashMap<>(); Map<FoldingGroup, Boolean> groupExpand = new THashMap<>(); List<FoldRegion> newRegions = addNewRegions(info, foldingModel, rangeToExpandStatusMap, shouldExpand, groupExpand); applyExpandStatus(newRegions, shouldExpand, groupExpand); foldingModel.clearDocumentRangesModificationStatus(); }
@Nullable private List<NamedFoldingDescriptor> createDescriptors(PsiElement classRBrace, int rangeStart, int rangeEnd, String header, String footer) { if(rangeStart >= rangeEnd) { return null; } FoldingGroup group = FoldingGroup.newGroup("lambda"); List<NamedFoldingDescriptor> foldElements = new ArrayList<>(); foldElements.add(new NamedFoldingDescriptor(myNewExpression, getClosureStartOffset(), rangeStart, group, header)); if(rangeEnd + 1 < getClosureEndOffset()) { foldElements.add(new NamedFoldingDescriptor(classRBrace, rangeEnd, getClosureEndOffset(), group, footer)); } return foldElements; }
@Nullable private FoldingDescriptor foldRouteReferenceString(PsiReference reference, String value, FoldingGroup group) { PsiElement element = reference.getElement(); TextRange foldingRange = new TextRange(element.getTextRange().getStartOffset() + 1, element.getTextRange().getEndOffset() - 1); if (!RouteIndex.hasRoute(element.getProject(), value)) { return null; } Collection<RouteStub> route = RouteIndex.getRoute(element.getProject(), value); if (route.size() == 0) { return null; } RouteStub routeDef = route.iterator().next(); return new FoldingDescriptor(element.getNode(), foldingRange, group) { @Nullable @Override public String getPlaceholderText() { if (routeDef.getPath() == null) { return routeDef.getController() + "::" + routeDef.getMethod(); } return routeDef.getPath(); } }; }
@NotNull @Override public FoldingDescriptor[] buildFoldRegions( @NotNull final PsiElement root, @NotNull final Document document, final boolean quick ) { if (this.isFoldingDisabled()) { return EMPTY_ARRAY; } Validate.notNull(root); Validate.notNull(document); final Collection<PsiElement> psiElements = this.findFoldingBlocksAndLineBreaks(root); FoldingGroup currentLineGroup = FoldingGroup.newGroup(GROUP_NAME); /* Avoid spawning a lot of unnecessary objects for each line break. */ boolean groupIsNotFresh = false; final List<FoldingDescriptor> descriptors = newArrayList(); for (final PsiElement psiElement : psiElements) { if (isLineBreak(psiElement)) { if (groupIsNotFresh) { currentLineGroup = FoldingGroup.newGroup(GROUP_NAME); groupIsNotFresh = false; } } else { descriptors.add(new ImpexFoldingDescriptor(psiElement, currentLineGroup)); groupIsNotFresh = true; } } return descriptors.toArray(new FoldingDescriptor[descriptors.size()]); }
public ImpexFoldingDescriptor( @NotNull final PsiElement psiElement, @NotNull final FoldingGroup group ) { super( psiElement.getNode(), new TextRange( psiElement.getTextRange().getStartOffset(), psiElement.getTextRange().getEndOffset() ), group ); placeholder = ImpexFoldingPlaceholderBuilderFactory.getPlaceholderBuilder().getPlaceholder(psiElement); }
public ImpexFoldingDescriptor( @NotNull final PsiElement psiElement, final int startOffset, final int endOffset, @NotNull final FoldingGroup group, Function<PsiElement, String> placeholderFunction ) { super(psiElement.getNode(), new TextRange(startOffset, endOffset), group); placeholder = placeholderFunction.apply(psiElement); }
/** * Creates a folding region related to the specified AST node and covering the specified * text range. * @param node The node to which the folding region is related. The node is then passed to * {@link com.intellij.lang.folding.FoldingBuilder#getPlaceholderText(com.intellij.lang.ASTNode)} and * {@link com.intellij.lang.folding.FoldingBuilder#isCollapsedByDefault(com.intellij.lang.ASTNode)}. * @param range The folded text range. * @param group Regions with the same group instance expand and collapse together. * @param dependencies folding dependencies: other files or elements that could change * @param neverExpands shall be true for fold regions that must not be ever expanded. */ public FoldingDescriptor(@NotNull ASTNode node, @NotNull TextRange range, @Nullable FoldingGroup group, Set<Object> dependencies, boolean neverExpands) { assert range.getLength() > 0 : range + ", text: " + node.getText() + ", language = " + node.getPsi().getLanguage(); myElement = node; myRange = range; myGroup = group; myDependencies = dependencies; assert !myDependencies.contains(null); myNeverExpands = neverExpands; }
FoldRegionImpl(@NotNull Editor editor, int startOffset, int endOffset, @NotNull String placeholder, @Nullable FoldingGroup group, boolean shouldNeverExpand) { super((DocumentEx)editor.getDocument(), startOffset, endOffset,true); myGroup = group; myShouldNeverExpand = shouldNeverExpand; myIsExpanded = true; myEditor = editor; myPlaceholderText = placeholder; }
public Collection<DisplayedFoldingAnchor> getAnchorsToDisplay(int firstVisibleOffset, int lastVisibleOffset, FoldRegion activeFoldRegion) { Map<Integer, DisplayedFoldingAnchor> result = new HashMap<Integer, DisplayedFoldingAnchor>(); FoldRegion[] visibleFoldRegions = myEditor.getFoldingModel().fetchVisible(); for (FoldRegion region : visibleFoldRegions) { if (!region.isValid()) continue; final int startOffset = region.getStartOffset(); if (startOffset > lastVisibleOffset) continue; final int endOffset = getEndOffset(region); if (endOffset < firstVisibleOffset) continue; if (!isFoldingPossible(startOffset, endOffset)) continue; final FoldingGroup group = region.getGroup(); if (group != null && myEditor.getFoldingModel().getFirstRegion(group, region) != region) continue; //offset = Math.min(myEditor.getDocument().getTextLength() - 1, offset); int foldStart = myEditor.offsetToVisualLine(startOffset); if (!region.isExpanded()) { tryAdding(result, region, foldStart, 0, DisplayedFoldingAnchor.Type.COLLAPSED, activeFoldRegion); } else { //offset = Math.min(myEditor.getDocument().getTextLength() - 1, offset); int foldEnd = myEditor.offsetToVisualLine(endOffset); tryAdding(result, region, foldStart, foldEnd - foldStart, DisplayedFoldingAnchor.Type.EXPANDED_TOP, activeFoldRegion); tryAdding(result, region, foldEnd, foldEnd - foldStart, DisplayedFoldingAnchor.Type.EXPANDED_BOTTOM, activeFoldRegion); } } return result.values(); }
public NamedFoldingDescriptor(@NotNull ASTNode node, @NotNull final TextRange range, @Nullable FoldingGroup group, @NotNull String placeholderText) { super(node, range, group); myPlaceholderText = placeholderText; }
private static void applyExpandStatus(@NotNull List<FoldRegion> newRegions, @NotNull Map<FoldRegion, Boolean> shouldExpand, @NotNull Map<FoldingGroup, Boolean> groupExpand) { for (final FoldRegion region : newRegions) { final FoldingGroup group = region.getGroup(); final Boolean expanded = group == null ? shouldExpand.get(region) : groupExpand.get(group); if (expanded != null) { region.setExpanded(expanded.booleanValue()); } } }
@Override public FoldRegion createFoldRegion(int startOffset, int endOffset, @NotNull String placeholder, FoldingGroup group, boolean neverExpands) { TextRange hostRange = myDocumentWindow.injectedToHost(new TextRange(startOffset, endOffset)); if (hostRange.getLength() < 2) return null; FoldRegion hostRegion = myDelegate.createFoldRegion(hostRange.getStartOffset(), hostRange.getEndOffset(), placeholder, group, neverExpands); int startShift = Math.max(0, myDocumentWindow.hostToInjected(hostRange.getStartOffset()) - startOffset); int endShift = Math.max(0, endOffset - myDocumentWindow.hostToInjected(hostRange.getEndOffset()) - startShift); FoldingRegionWindow window = new FoldingRegionWindow(myDocumentWindow, myEditorWindow, hostRegion, startShift, endShift); hostRegion.putUserData(FOLD_REGION_WINDOW, window); return window; }
/** * Creates a folding region related to the specified AST node and covering the specified * text range. * @param node The node to which the folding region is related. The node is then passed to * {@link com.intellij.lang.folding.FoldingBuilder#getPlaceholderText(com.intellij.lang.ASTNode)} and * {@link com.intellij.lang.folding.FoldingBuilder#isCollapsedByDefault(com.intellij.lang.ASTNode)}. * @param range The folded text range. * @param group Regions with the same group instance expand and collapse together. * @param dependencies folding dependencies: other files or elements that could change * @param neverExpands shall be true for fold regions that must not be ever expanded. */ public FoldingDescriptor(@NotNull ASTNode node, @NotNull TextRange range, @Nullable FoldingGroup group, Set<Object> dependencies, boolean neverExpands) { assert range.getStartOffset() + 1 < range.getEndOffset() : range + ", text: " + node.getText() + ", language = " + node.getPsi().getLanguage(); myElement = node; ProperTextRange.assertProperRange(range); myRange = range; myGroup = group; assert getRange().getLength() >= 2 : "range:" + getRange(); myDependencies = dependencies; myNeverExpands = neverExpands; }
public int getEndOffset(@NotNull FoldingGroup group) { final List<FoldRegion> regions = getGroupedRegions(group); int endOffset = 0; for (FoldRegion region : regions) { if (region.isValid()) { endOffset = Math.max(endOffset, region.getEndOffset()); } } return endOffset; }
@Override public FoldRegion createFoldRegion(int startOffset, int endOffset, @NotNull String placeholder, @Nullable FoldingGroup group, boolean neverExpands) { if (startOffset + 1 >= endOffset) { LOG.error("Invalid offsets: ("+startOffset+", "+endOffset+")"); } FoldRegionImpl region = new FoldRegionImpl(myEditor, startOffset, endOffset, placeholder, group, neverExpands); LOG.assertTrue(region.isValid()); return region; }
@Override public void run() { EditorFoldingInfo info = EditorFoldingInfo.get(myEditor); FoldingModelEx foldingModel = (FoldingModelEx)myEditor.getFoldingModel(); Map<TextRange,Boolean> rangeToExpandStatusMap = newTroveMap(); removeInvalidRegions(info, foldingModel, rangeToExpandStatusMap); Map<FoldRegion, Boolean> shouldExpand = newTroveMap(); Map<FoldingGroup, Boolean> groupExpand = newTroveMap(); List<FoldRegion> newRegions = addNewRegions(info, foldingModel, rangeToExpandStatusMap, shouldExpand, groupExpand); applyExpandStatus(newRegions, shouldExpand, groupExpand); }
@Override public FoldRegion createFoldRegion(int startOffset, int endOffset, @NotNull String placeholder, FoldingGroup group, boolean neverExpands) { TextRange hostRange = myDocumentWindow.injectedToHost(new TextRange(startOffset, endOffset)); if (hostRange.getLength() < 2) return null; FoldRegion hostRegion = myDelegate.createFoldRegion(hostRange.getStartOffset(), hostRange.getEndOffset(), placeholder, group, neverExpands); int startShift = Math.max(0, myDocumentWindow.hostToInjected(hostRange.getStartOffset()) - startOffset); int endShift = Math.max(0, endOffset - myDocumentWindow.hostToInjected(hostRange.getEndOffset()) - startShift); FoldingRegionWindow window = new FoldingRegionWindow(myDocumentWindow, myEditorWindow, (FoldRegionImpl)hostRegion, startShift, endShift); hostRegion.putUserData(FOLD_REGION_WINDOW, window); return window; }
/** * Creates a folding region related to the specified AST node and covering the specified * text range. * @param node The node to which the folding region is related. The node is then passed to * {@link com.intellij.lang.folding.FoldingBuilder#getPlaceholderText(com.intellij.lang.ASTNode)} and * {@link com.intellij.lang.folding.FoldingBuilder#isCollapsedByDefault(com.intellij.lang.ASTNode)}. * @param range The folded text range. * @param group Regions with the same group instance expand and collapse together. * @param dependencies folding dependencies: other files or elements that could change * @param neverExpands shall be true for fold regions that must not be ever expanded. */ public FoldingDescriptor(@Nonnull ASTNode node, @Nonnull TextRange range, @Nullable FoldingGroup group, Set<Object> dependencies, boolean neverExpands) { assert range.getLength() > 0 : range + ", text: " + node.getText() + ", language = " + node.getPsi().getLanguage(); myElement = node; myRange = range; myGroup = group; myDependencies = dependencies; assert !myDependencies.contains(null); myNeverExpands = neverExpands; }
FoldRegionImpl(@Nonnull EditorImpl editor, int startOffset, int endOffset, @Nonnull String placeholder, @Nullable FoldingGroup group, boolean shouldNeverExpand) { super(editor.getDocument(), startOffset, endOffset,false); myGroup = group; myShouldNeverExpand = shouldNeverExpand; myIsExpanded = true; myEditor = editor; myPlaceholderText = placeholder; }
public NamedFoldingDescriptor(@Nonnull ASTNode node, @Nonnull final TextRange range, @Nullable FoldingGroup group, @Nonnull String placeholderText) { super(node, range, group); myPlaceholderText = placeholderText; }
private static void applyExpandStatus(@Nonnull List<FoldRegion> newRegions, @Nonnull Map<FoldRegion, Boolean> shouldExpand, @Nonnull Map<FoldingGroup, Boolean> groupExpand) { for (final FoldRegion region : newRegions) { final FoldingGroup group = region.getGroup(); final Boolean expanded = group == null ? shouldExpand.get(region) : groupExpand.get(group); if (expanded != null) { region.setExpanded(expanded.booleanValue()); } } }
private boolean regionOrGroupCanBeRemovedWhenCollapsed(FoldRegion region) { FoldingGroup group = region.getGroup(); List<FoldRegion> affectedRegions = group != null && myEditor instanceof EditorEx ? ((EditorEx)myEditor).getFoldingModel().getGroupedRegions(group) : Collections.singletonList(region); for (FoldRegion affectedRegion : affectedRegions) { if (regionCanBeRemovedWhenCollapsed(affectedRegion)) return true; } return false; }
@Override public FoldRegion createFoldRegion(int startOffset, int endOffset, @Nonnull String placeholder, FoldingGroup group, boolean neverExpands) { TextRange hostRange = myDocumentWindow.injectedToHost(new TextRange(startOffset, endOffset)); if (hostRange.getLength() < 2) return null; FoldRegion hostRegion = myDelegate.createFoldRegion(hostRange.getStartOffset(), hostRange.getEndOffset(), placeholder, group, neverExpands); if (hostRegion == null) return null; int startShift = Math.max(0, myDocumentWindow.hostToInjected(hostRange.getStartOffset()) - startOffset); int endShift = Math.max(0, endOffset - myDocumentWindow.hostToInjected(hostRange.getEndOffset()) - startShift); FoldingRegionWindow window = new FoldingRegionWindow(myDocumentWindow, myEditorWindow, hostRegion, startShift, endShift); hostRegion.putUserData(FOLD_REGION_WINDOW, window); return window; }
@Nonnull @Override public List<FoldRegion> getGroupedRegions(FoldingGroup group) { List<FoldRegion> hostRegions = myDelegate.getGroupedRegions(group); List<FoldRegion> result = new ArrayList<>(); for (FoldRegion hostRegion : hostRegions) { FoldingRegionWindow window = getWindowRegion(hostRegion); if (window != null) result.add(window); } return result; }
@NotNull @Override public FoldingDescriptor[] buildFoldRegions(@NotNull PsiElement root, @NotNull Document document, boolean quick) { FoldingGroup group = FoldingGroup.newGroup("TYPO3Translation"); List<FoldingDescriptor> descriptors = new ArrayList<>(); Collection<StringLiteralExpression> literalExpressions = PsiTreeUtil.findChildrenOfType(root, StringLiteralExpression.class); for (final StringLiteralExpression literalExpression : literalExpressions) { String value = literalExpression.getContents(); if (value.startsWith("LLL:")) { Project project = literalExpression.getProject(); final List<StubTranslation> properties = TranslationIndex.findById(project, value); StubTranslation defaultTranslation = findDefaultTranslationFromVariants(properties); if (defaultTranslation != null) { TextRange foldingRange = new TextRange(literalExpression.getTextRange().getStartOffset() + 1, literalExpression.getTextRange().getEndOffset() - 1); descriptors.add(new FoldingDescriptor(literalExpression.getNode(), foldingRange, group) { @Nullable @Override public String getPlaceholderText() { PsiElement[] definitionElements = TranslationUtil.findDefinitionElements(project, value); for (PsiElement definitionElement : definitionElements) { if (definitionElement instanceof XmlTag) { if (((XmlTag) definitionElement).getName().equals("label")) { return ((XmlTag) definitionElement).getValue().getTrimmedText(); } for (XmlTag xmlTag : ((XmlTag) definitionElement).getSubTags()) { if (xmlTag.getName().equals("source")) { return xmlTag.getValue().getTrimmedText(); } } } } return null; } }); } } } return descriptors.toArray(new FoldingDescriptor[descriptors.size()]); }
private static void processDirectives( @Nullable final BladePsiDirective baseDirective, @NotNull final Queue<BladePsiDirective> directives, @NotNull final Collection<FoldingDescriptor> foldingDescriptors, @NotNull final Document document ) { while (true) { final BladePsiDirective directive = directives.peek(); if (directive == null) { break; } if (IGNORED_DIRECTIVES.contains(directive.getName())) { directives.poll(); continue; } if (baseDirective == null) { if (!directive.isToBeClosed()) { directives.poll(); continue; } processDirectives(directives.poll(), directives, foldingDescriptors, document); continue; } // Eg. @endif or @elseif closes @if. // Or that @elseif continues @if. if (directive.closes(baseDirective) || directive.continues(baseDirective)) { // Eg. @endif closes definitively an @if, @else or @elseif. // But @elseif or @else don't have the same effect. final boolean isDefinitivelyClosing = directive.isClosing() && !directive.isContinued(); final TextRange foldingRange = new TextRange( baseDirective.getTextRange().getEndOffset(), directive.getTextRange().getStartOffset() - calculateEndOffsetReductor(directive, isDefinitivelyClosing) ); if ((foldingRange.getLength() > 0) && !StringUtils.strip(document.getText(foldingRange), " ").isEmpty()) { foldingDescriptors.add(new FoldingDescriptor(baseDirective.getNode(), foldingRange, FoldingGroup.newGroup("Blade"))); } if (isDefinitivelyClosing) { directives.poll(); break; } processDirectives(directives.poll(), directives, foldingDescriptors, document); break; } // Eg. @if or @elseif (but it will be catched on previous condition). if (directive.isContinued()) { processDirectives(directives.poll(), directives, foldingDescriptors, document); continue; } directives.poll(); } }
@NotNull @Override public FoldingDescriptor[] buildFoldRegions( @NotNull final PsiElement root, @NotNull final Document document, final boolean quick ) { if (this.isFoldingDisabled()) { return EMPTY_ARRAY; } Validate.notNull(root); Validate.notNull(document); FoldingGroup currentLineGroup = FoldingGroup.newGroup(LINE_GROUP_NAME); final List<PsiElement> foldingBlocks = foldingLines(root); PsiElement startGroupElement = foldingBlocks.isEmpty() ? null : foldingBlocks.get(0); final List<FoldingDescriptor> descriptors = newArrayList(); /* Avoid spawning a lot of unnecessary objects for each line break. */ boolean groupIsNotFresh = false; final int size = foldingBlocks.size(); int countLinesOnGroup = 0; for (int i = 0; i < size; i++) { final int nextIdx = Math.min(i + 1, size - 1); final PsiElement element = foldingBlocks.get(i); if (isHeaderLine(element) || isUserRightsMacros(element)) { startGroupElement = foldingBlocks.get(nextIdx); if (groupIsNotFresh) { currentLineGroup = FoldingGroup.newGroup(LINE_GROUP_NAME); countLinesOnGroup = 0; groupIsNotFresh = false; } } else { if (nextElementIsHeaderLine(element) || nextElementIsUserRightsMacros(element) || nextIdx == size) { if (countLinesOnGroup > 1) { descriptors.add(new ImpexFoldingDescriptor( startGroupElement, startGroupElement.getStartOffsetInParent(), element.getTextRange().getEndOffset(), currentLineGroup, (elm) -> { final PsiElement prevSibling = getPrevNonWhitespaceElement(elm); if (prevSibling != null && (isHeaderLine(prevSibling) || isUserRightsMacros(prevSibling))) { return ";....;...."; } return ""; } )); } groupIsNotFresh = true; } } if (isImpexValueLine(element)) { countLinesOnGroup++; } } return descriptors.toArray(new FoldingDescriptor[descriptors.size()]); }
private boolean addOneLineMethodFolding(List<FoldingDescriptor> descriptorList, PsiMethod method) { if (!JavaCodeFoldingSettings.getInstance().isCollapseOneLineMethods()) { return false; } Document document = method.getContainingFile().getViewProvider().getDocument(); PsiCodeBlock body = method.getBody(); PsiIdentifier nameIdentifier = method.getNameIdentifier(); if (body == null || document == null || nameIdentifier == null) { return false; } if (document.getLineNumber(nameIdentifier.getTextRange().getStartOffset()) != document.getLineNumber(method.getParameterList().getTextRange().getEndOffset())) { return false; } PsiJavaToken lBrace = body.getLBrace(); PsiJavaToken rBrace = body.getRBrace(); PsiStatement[] statements = body.getStatements(); if (lBrace == null || rBrace == null || statements.length != 1) { return false; } PsiStatement statement = statements[0]; if (statement.textContains('\n')) { return false; } if (!areOnAdjacentLines(lBrace, statement, document) || !areOnAdjacentLines(statement, rBrace, document)) { //the user might intend to type at an empty line return false; } int leftStart = method.getParameterList().getTextRange().getEndOffset(); int bodyStart = body.getTextRange().getStartOffset(); if (bodyStart > leftStart && !StringUtil.isEmptyOrSpaces(document.getCharsSequence().subSequence(leftStart + 1, bodyStart))) { return false; } int leftEnd = statement.getTextRange().getStartOffset(); int rightStart = statement.getTextRange().getEndOffset(); int rightEnd = body.getTextRange().getEndOffset(); if (leftEnd <= leftStart + 1 || rightEnd <= rightStart + 1) { return false; } String leftText = " { "; String rightText = " }"; if (!fitsRightMargin(method, document, leftStart, rightEnd, rightStart - leftEnd + leftText.length() + rightText.length())) { return false; } FoldingGroup group = FoldingGroup.newGroup("one-liner"); descriptorList.add(new NamedFoldingDescriptor(lBrace, leftStart, leftEnd, group, leftText)); descriptorList.add(new NamedFoldingDescriptor(rBrace, rightStart, rightEnd, group, rightText)); return true; }
public FoldingDescriptor(@NotNull ASTNode node, @NotNull TextRange range, @Nullable FoldingGroup group) { this(node, range, group, Collections.<Object>emptySet()); }