/*
* Copyright 2013-2017 consulo.io
*
* 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 consulo.csharp.lang.formatter;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.List;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import consulo.annotations.RequiredReadAction;
import consulo.csharp.ide.codeStyle.CSharpCodeStyleSettings;
import consulo.csharp.lang.CSharpLanguage;
import consulo.csharp.lang.formatter.processors.CSharpIndentProcessor;
import consulo.csharp.lang.formatter.processors.CSharpSpacingProcessor;
import consulo.csharp.lang.formatter.processors.CSharpWrappingProcessor;
import consulo.csharp.lang.psi.CSharpElements;
import consulo.csharp.lang.psi.CSharpTokenSets;
import consulo.csharp.lang.psi.CSharpTokens;
import com.intellij.formatting.ASTBlock;
import com.intellij.formatting.Alignment;
import com.intellij.formatting.Block;
import com.intellij.formatting.Indent;
import com.intellij.formatting.Spacing;
import com.intellij.formatting.Wrap;
import com.intellij.formatting.templateLanguages.BlockWithParent;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.formatter.FormatterUtil;
import com.intellij.psi.formatter.common.AbstractBlock;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.containers.ContainerUtil;
/**
* @author VISTALL
* @since 15.12.13.
*/
public class CSharpFormattingBlock extends AbstractBlock implements CSharpElements, CSharpTokens, CSharpTokenSets, BlockWithParent
{
private final CSharpWrappingProcessor myWrappingProcessor;
private final CSharpIndentProcessor myIndentProcessor;
private final CSharpSpacingProcessor mySpacingProcessor;
private CodeStyleSettings mySettings;
private List<ASTNode> myAdditionalNodes = Collections.emptyList();
private CSharpFormattingBlock myParent;
public CSharpFormattingBlock(@NotNull ASTNode node, @Nullable Wrap wrap, @Nullable Alignment alignment, @NotNull CodeStyleSettings settings)
{
super(node, wrap, alignment);
mySettings = settings;
CommonCodeStyleSettings commonSettings = settings.getCommonSettings(CSharpLanguage.INSTANCE);
CSharpCodeStyleSettings customSettings = settings.getCustomSettings(CSharpCodeStyleSettings.class);
myWrappingProcessor = new CSharpWrappingProcessor(node, commonSettings, customSettings);
myIndentProcessor = new CSharpIndentProcessor(this, commonSettings, customSettings);
mySpacingProcessor = new CSharpSpacingProcessor(this, commonSettings, customSettings);
}
@Nullable
@Override
public Spacing getSpacing(@Nullable Block child1, @NotNull Block child2)
{
return mySpacingProcessor.getSpacing((ASTBlock) child1, (ASTBlock) child2);
}
@Override
public boolean isLeaf()
{
return getNode().getFirstChildNode() == null;
}
@NotNull
@Override
public TextRange getTextRange()
{
TextRange textRange = super.getTextRange();
if(!myAdditionalNodes.isEmpty())
{
return new TextRange(textRange.getStartOffset(), ContainerUtil.getLastItem(myAdditionalNodes).getTextRange().getEndOffset());
}
return textRange;
}
@Override
protected List<Block> buildChildren()
{
if(isLeaf())
{
return EMPTY;
}
List<Block> children = new ArrayList<Block>(5);
Deque<ASTNode> nodes = new ArrayDeque<ASTNode>(5);
for(ASTNode childNode = getNode().getFirstChildNode(); childNode != null; childNode = childNode.getTreeNext())
{
if(FormatterUtil.containsWhiteSpacesOnly(childNode))
{
continue;
}
nodes.add(childNode);
}
nodes.addAll(myAdditionalNodes);
ASTNode next;
while((next = nodes.poll()) != null)
{
final CSharpFormattingBlock childBlock = new CSharpFormattingBlock(next, null, null, mySettings);
childBlock.setParent(this);
IElementType elementType = next.getElementType();
if(elementType == SWITCH_LABEL_STATEMENT)
{
ASTNode someNextElement;
while((someNextElement = nodes.poll()) != null)
{
IElementType someNextElementType = someNextElement.getElementType();
if(someNextElementType == SWITCH_LABEL_STATEMENT || someNextElementType == RBRACE)
{
nodes.addFirst(someNextElement);
break;
}
childBlock.addAdditionalNode(someNextElement);
}
}
children.add(childBlock);
}
return children;
}
public void addAdditionalNode(ASTNode node)
{
if(myAdditionalNodes.isEmpty())
{
myAdditionalNodes = new ArrayList<ASTNode>(5);
}
myAdditionalNodes.add(node);
}
@Nullable
@Override
public Wrap getWrap()
{
return myWrappingProcessor.getWrap();
}
@Override
@RequiredReadAction
public Indent getIndent()
{
return myIndentProcessor.getIndent();
}
@Nullable
@Override
protected Indent getChildIndent()
{
return myIndentProcessor.getChildIndent();
}
@Override
public CSharpFormattingBlock getParent()
{
return myParent;
}
@Override
public void setParent(BlockWithParent newParent)
{
myParent = (CSharpFormattingBlock) newParent;
}
@NotNull
@RequiredReadAction
public IElementType getElementType()
{
IElementType elementType = getNode().getElementType();
assert elementType != null : getNode().getText();
return elementType;
}
}