Expandable indent storing additional block, which indent is used as min indent marker for all children of blocks corresponding to particular expandable indent.

If all blocks corresponding to current expandable indent has no linefeeds in their whitespaces, if one of these blocks has child which has indent less or equal than min marker indent, than indent is expanded.

Total summary:
Indent is expanded, if any of blocks with these indent is located on new line, or when there is some block's children with indent less or equal than min marker indent.
This commit is contained in:
Yaroslav Lepenkin
2015-09-02 12:35:07 +03:00
parent 6c3ee1c84b
commit 03a72e58c3
7 changed files with 73 additions and 70 deletions
@@ -867,9 +867,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
Indent internalIndent = Indent.getContinuationWithoutFirstIndent(myIndentSettings.USE_RELATIVE_INDENTS);
if (isInsideMethodCallParenthesis(child)) {
Object group = new Object();
externalIndent = Indent.getSmartIndentMinOffsetMarker(Indent.Type.NONE, group);
internalIndent = Indent.getSmartIndent(Indent.Type.CONTINUATION, group);
internalIndent = Indent.getSmartIndent(Indent.Type.CONTINUATION);
}
AlignmentStrategy alignmentStrategy = AlignmentStrategy.wrap(createAlignment(doAlign, null), JavaTokenType.COMMA);
@@ -904,11 +902,14 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
result.add(createJavaBlock(child, mySettings, myJavaSettings, externalIndent, null, bracketAlignment));
}
else if (child.getElementType() == to) {
result.add(createJavaBlock(child, mySettings, myJavaSettings,
isAfterIncomplete && !afterAnonymousClass ? internalIndent : externalIndent,
null,
isAfterIncomplete ? alignmentStrategy.getAlignment(null) : bracketAlignment)
);
Block block = createJavaBlock(child, mySettings, myJavaSettings,
isAfterIncomplete && !afterAnonymousClass ? internalIndent : externalIndent,
null,
isAfterIncomplete ? alignmentStrategy.getAlignment(null) : bracketAlignment);
result.add(block);
if (internalIndent instanceof ExpandableIndent && to == JavaTokenType.RPARENTH) {
((ExpandableIndent)internalIndent).setStrictMinOffsetBlock(block);
}
return child;
}
else {
@@ -269,12 +269,8 @@ public abstract class Indent {
return myFactory.getIndent(type, spaces, relativeToDirectParent, enforceIndentToChildren);
}
public static Indent getSmartIndent(Type type, Object group) {
return myFactory.getSmartIndent(type, group);
}
public static Indent getSmartIndentMinOffsetMarker(Type type, Object group) {
return myFactory.getSmartIndentMinOffsetMarker(type, group);
public static Indent getSmartIndent(Type type) {
return myFactory.getSmartIndent(type);
}
public static class Type {
@@ -34,6 +34,5 @@ interface IndentFactory {
Indent getSpaceIndent(final int spaces, boolean relativeToDirectParent);
Indent getIndent(@NotNull Indent.Type type, boolean relativeToDirectParent, boolean enforceIndentToChildren);
Indent getIndent(@NotNull Indent.Type type, int spaces, boolean relativeToDirectParent, boolean enforceIndentToChildren);
Indent getSmartIndent(@NotNull Indent.Type type, @NotNull Object group);
Indent getSmartIndentMinOffsetMarker(@NotNull Indent.Type type, @NotNull Object group);
Indent getSmartIndent(@NotNull Indent.Type type);
}
@@ -16,30 +16,22 @@
package com.intellij.formatting;
public class ExpandableIndent extends IndentImpl {
private final Object myGroup;
private boolean myMinGroupOffsetMarker;
private Block myStrictMinOffsetBlock;
private boolean myEnforceIndent;
public ExpandableIndent(Type type, Object group) {
public ExpandableIndent(Type type) {
super(type, false, 0, false, true);
myGroup = group;
myEnforceIndent = false;
}
public boolean isMinGroupOffsetMarker() {
return myMinGroupOffsetMarker;
public void setStrictMinOffsetBlock(Block block) {
myStrictMinOffsetBlock = block;
}
void setMinGroupOffsetMarker(boolean value) {
myMinGroupOffsetMarker = value;
Block getStrictMinOffsetBlock() {
return myStrictMinOffsetBlock;
}
public Object getGroup() {
return myGroup;
}
@Override
public boolean isEnforceIndentToChildren() {
return myEnforceIndent;
@@ -159,7 +159,8 @@ public class FormatProcessor {
@NotNull
private State myCurrentState;
private MultiMap<Object, AbstractBlockWrapper> myExpandableIndents;
private MultiMap<ExpandableIndent, AbstractBlockWrapper> myExpandableIndents;
private Map<Block, AbstractBlockWrapper> myExpandableIndentsMinOffsetBlocksToWrappers;
public FormatProcessor(final FormattingDocumentModel docModel,
Block rootBlock,
@@ -1365,7 +1366,9 @@ public class FormatProcessor {
root, model, affectedRanges, mySettings, myDefaultIndentOption, interestingOffset, myProgressCallback
);
myWrapper.setCollectAlignmentsInsideFormattingRange(myReformatContext);
myExpandableIndents = myWrapper.getBlocksWithSmartIndents();
myExpandableIndents = myWrapper.getExpandableIndentsBlocks();
myExpandableIndentsMinOffsetBlocksToWrappers = myWrapper.getMarkerBlocks();
}
@Override
@@ -1590,9 +1593,8 @@ public class FormatProcessor {
}
}
private class ExpandChildrenIndent extends State {
private Iterator<Object> myIterator;
private Iterator<ExpandableIndent> myIterator;
public ExpandChildrenIndent() {
super(FormattingStateId.EXPANDING_CHILDREN_INDENTS);
@@ -1608,11 +1610,10 @@ public class FormatProcessor {
return;
}
Collection<AbstractBlockWrapper> blocksToExpandIndent = myExpandableIndents.get(myIterator.next());
if (shouldExpand(blocksToExpandIndent)) {
final ExpandableIndent indent = myIterator.next();
Collection<AbstractBlockWrapper> blocksToExpandIndent = myExpandableIndents.get(indent);
if (shouldExpand(indent, blocksToExpandIndent)) {
for (AbstractBlockWrapper block : blocksToExpandIndent) {
ExpandableIndent indent = (ExpandableIndent)block.getIndent();
indent.setEnforceIndent(true);
reindentNewLineChildren(block);
indent.setEnforceIndent(false);
@@ -1620,28 +1621,20 @@ public class FormatProcessor {
}
}
private boolean shouldExpand(Collection<AbstractBlockWrapper> blocksToExpandIndent) {
int minGroupOffset = Integer.MAX_VALUE;
private boolean shouldExpand(ExpandableIndent indent, Collection<AbstractBlockWrapper> blocksToExpandIndent) {
for (AbstractBlockWrapper block : blocksToExpandIndent) {
if (!block.getWhiteSpace().containsLineFeeds()) continue;
ExpandableIndent indent = (ExpandableIndent)block.getIndent();
if (indent.isMinGroupOffsetMarker()) {
minGroupOffset = block.getNumberOfSymbolsBeforeBlock().getTotalSpaces();
}
else {
return true;
}
return true;
}
if (minGroupOffset == Integer.MAX_VALUE) return false;
int strictMinOffset = getStrictMinOffset(indent);
if (strictMinOffset == Integer.MAX_VALUE) {
return false;
}
for (AbstractBlockWrapper block : blocksToExpandIndent) {
ExpandableIndent indent = (ExpandableIndent)block.getIndent();
if (indent.isMinGroupOffsetMarker()) continue;
int minNewLineChildrenOffset = findMinNewLineIndent(block);
if (minNewLineChildrenOffset <= minGroupOffset) {
if (minNewLineChildrenOffset <= strictMinOffset) {
return true;
}
}
@@ -1649,6 +1642,18 @@ public class FormatProcessor {
return false;
}
private int getStrictMinOffset(ExpandableIndent indent) {
final Block minOffsetBlock = indent.getStrictMinOffsetBlock();
if (minOffsetBlock == null) return Integer.MAX_VALUE;
AbstractBlockWrapper wrapper = myExpandableIndentsMinOffsetBlocksToWrappers.get(minOffsetBlock);
if (wrapper.getWhiteSpace().containsLineFeeds()) {
return wrapper.getNumberOfSymbolsBeforeBlock().getTotalSpaces();
}
return Integer.MAX_VALUE;
}
private int findMinNewLineIndent(@NotNull AbstractBlockWrapper block) {
if (block instanceof LeafBlockWrapper && block.getWhiteSpace().containsLineFeeds()) {
return block.getNumberOfSymbolsBeforeBlock().getTotalSpaces();
@@ -819,15 +819,8 @@ public class FormatterImpl extends FormatterEx
}
@Override
public Indent getSmartIndent(@NotNull Indent.Type type, @NotNull Object group) {
return new ExpandableIndent(type, group);
}
@Override
public Indent getSmartIndentMinOffsetMarker(@NotNull Indent.Type type, @NotNull Object group) {
ExpandableIndent indent = new ExpandableIndent(type, group);
indent.setMinGroupOffsetMarker(true);
return indent;
public Indent getSmartIndent(@NotNull Indent.Type type) {
return new ExpandableIndent(type);
}
@Override
@@ -76,7 +76,9 @@ class InitialInfoBuilder {
private Set<Alignment> myAlignmentsInsideRangeToModify = ContainerUtil.newHashSet();
private boolean myCollectAlignmentsInsideFormattingRange = false;
private MultiMap<Object, AbstractBlockWrapper> myBlocksToForceChildrenIndent = new LinkedMultiMap<Object, AbstractBlockWrapper>();
private Set<Block> myStrictMinOffsetBlocks = ContainerUtil.newHashSet();
private MultiMap<ExpandableIndent, AbstractBlockWrapper> myBlocksToForceChildrenIndent = new LinkedMultiMap<ExpandableIndent, AbstractBlockWrapper>();
private Map<Block, AbstractBlockWrapper> myMarkerIndentToBlock = ContainerUtil.newHashMap();
private InitialInfoBuilder(final Block rootBlock,
final FormattingDocumentModel model,
@@ -289,10 +291,14 @@ class InitialInfoBuilder {
return wrappedRootBlock;
}
public MultiMap<Object, AbstractBlockWrapper> getBlocksWithSmartIndents() {
public MultiMap<ExpandableIndent, AbstractBlockWrapper> getExpandableIndentsBlocks() {
return myBlocksToForceChildrenIndent;
}
public Map<Block, AbstractBlockWrapper> getMarkerBlocks() {
return myMarkerIndentToBlock;
}
private void doIteration(@NotNull State state) {
List<Block> subBlocks = state.parentBlock.getSubBlocks();
final int subBlocksCount = subBlocks.size();
@@ -311,11 +317,7 @@ class InitialInfoBuilder {
final AbstractBlockWrapper wrapper = buildFrom(
block, childBlockIndex, state.wrappedBlock, state.parentBlockWrap, state.parentBlock, childBlockIsRightBlock
);
if (block.getIndent() instanceof ExpandableIndent) {
ExpandableIndent expandableIndent = (ExpandableIndent)block.getIndent();
myBlocksToForceChildrenIndent.putValue(expandableIndent.getGroup(), wrapper);
}
registerExpandableIndents(block, wrapper);
if (wrapper.getIndent() == null) {
wrapper.setIndent((IndentImpl)block.getIndent());
@@ -334,7 +336,22 @@ class InitialInfoBuilder {
}
}
}
private void registerExpandableIndents(@NotNull Block block, @NotNull AbstractBlockWrapper wrapper) {
ExpandableIndent expandableIndent = block.getIndent() instanceof ExpandableIndent ? ((ExpandableIndent)block.getIndent()) : null;
if (expandableIndent != null) {
myBlocksToForceChildrenIndent.putValue(expandableIndent, wrapper);
Block markerBlock = expandableIndent.getStrictMinOffsetBlock();
if (markerBlock != null) {
myStrictMinOffsetBlocks.add(markerBlock);
}
}
if (myStrictMinOffsetBlocks.contains(block)) {
myMarkerIndentToBlock.put(block, wrapper);
}
}
private void setDefaultIndents(final List<AbstractBlockWrapper> list) {
if (!list.isEmpty()) {
for (AbstractBlockWrapper wrapper : list) {