2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.formatting.templateLanguages;
18 import com.intellij.formatting.ASTBlock;
19 import com.intellij.formatting.Block;
20 import com.intellij.formatting.Indent;
21 import com.intellij.formatting.Spacing;
22 import com.intellij.lang.ASTNode;
23 import com.intellij.openapi.util.Pair;
24 import com.intellij.openapi.util.TextRange;
25 import org.jetbrains.annotations.NotNull;
26 import org.jetbrains.annotations.Nullable;
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.List;
33 * @author Alexey Chmutov
41 public static List<DataLanguageBlockWrapper> buildChildWrappers(@NotNull final Block parent) {
42 assert !(parent instanceof DataLanguageBlockWrapper) : parent.getClass();
43 List<Block> children = parent.getSubBlocks();
44 if (children.size() == 0) return Collections.emptyList();
45 ArrayList<DataLanguageBlockWrapper> result = new ArrayList<DataLanguageBlockWrapper>(children.size());
46 DataLanguageBlockWrapper prevWrapper = null;
47 for (Block child : children) {
48 DataLanguageBlockWrapper currWrapper = createAndAddBlock(result, child, null);
49 if(currWrapper != null && prevWrapper != null) {
50 Spacing spacing = parent.getSpacing(prevWrapper.getOriginal(), currWrapper.getOriginal());
51 prevWrapper.setRightHandSpacing(currWrapper, spacing);
53 prevWrapper = currWrapper;
58 public static Pair<List<DataLanguageBlockWrapper>, List<DataLanguageBlockWrapper>> splitBlocksByRightBound(@NotNull Block parent, @NotNull TextRange bounds) {
59 final List<Block> subBlocks = parent.getSubBlocks();
60 if (subBlocks.size() == 0) return new Pair<List<DataLanguageBlockWrapper>, List<DataLanguageBlockWrapper>>(Collections.<DataLanguageBlockWrapper>emptyList(), Collections.<DataLanguageBlockWrapper>emptyList());
61 final ArrayList<DataLanguageBlockWrapper> before = new ArrayList<DataLanguageBlockWrapper>(subBlocks.size() / 2);
62 final ArrayList<DataLanguageBlockWrapper> after = new ArrayList<DataLanguageBlockWrapper>(subBlocks.size() / 2);
63 splitByRightBoundAndCollectBlocks(subBlocks, before, after, bounds);
64 return new Pair<List<DataLanguageBlockWrapper>, List<DataLanguageBlockWrapper>>(before, after);
67 private static void splitByRightBoundAndCollectBlocks(@NotNull List<Block> blocks,
68 @NotNull List<DataLanguageBlockWrapper> before,
69 @NotNull List<DataLanguageBlockWrapper> after,
70 @NotNull TextRange bounds) {
71 for (Block block : blocks) {
72 final TextRange textRange = block.getTextRange();
73 if (bounds.contains(textRange)) {
74 createAndAddBlock(before, block, null);
76 else if (bounds.getEndOffset() < textRange.getStartOffset()) {
77 createAndAddBlock(after, block, null);
80 splitByRightBoundAndCollectBlocks(block.getSubBlocks(), before, after, bounds);
86 private static DataLanguageBlockWrapper createAndAddBlock(List<DataLanguageBlockWrapper> list, Block block, @Nullable final Indent indent) {
87 DataLanguageBlockWrapper wrapper = DataLanguageBlockWrapper.create(block, indent);
88 if (wrapper != null) {
95 public static List<Block> mergeBlocks(@NotNull List<TemplateLanguageBlock> tlBlocks, @NotNull List<DataLanguageBlockWrapper> foreignBlocks) {
96 ArrayList<Block> result = new ArrayList<Block>(tlBlocks.size() + foreignBlocks.size());
99 while (vInd < tlBlocks.size() && fInd < foreignBlocks.size()) {
100 final TemplateLanguageBlock v = tlBlocks.get(vInd);
101 final DataLanguageBlockWrapper f = foreignBlocks.get(fInd);
102 final TextRange vRange = v.getTextRange();
103 final TextRange fRange = f.getTextRange();
104 if (vRange.getStartOffset() >= fRange.getEndOffset()) {
105 // add leading foreign blocks
109 else if (vRange.getEndOffset() <= fRange.getStartOffset()) {
110 // add leading TL blocks
114 else if (vRange.getStartOffset() < fRange.getStartOffset() ||
115 vRange.getStartOffset() == fRange.getStartOffset() && vRange.getEndOffset() >= fRange.getEndOffset()) {
116 // add including TL blocks and split intersecting foreign blocks
118 while (fInd < foreignBlocks.size() && vRange.contains(foreignBlocks.get(fInd).getTextRange())) {
119 v.addForeignChild(foreignBlocks.get(fInd++));
121 if (fInd < foreignBlocks.size()) {
122 final DataLanguageBlockWrapper notContainedF = foreignBlocks.get(fInd);
123 if (vRange.intersectsStrict(notContainedF.getTextRange())) {
124 Pair<List<DataLanguageBlockWrapper>, List<DataLanguageBlockWrapper>> splitBlocks = splitBlocksByRightBound(notContainedF.getOriginal(), vRange);
125 v.addForeignChildren(splitBlocks.getFirst());
126 foreignBlocks.remove(fInd);
127 if (splitBlocks.getSecond().size() > 0) {
128 foreignBlocks.addAll(fInd, splitBlocks.getSecond());
134 else if (vRange.getStartOffset() > fRange.getStartOffset() ||
135 vRange.getStartOffset() == fRange.getStartOffset() && vRange.getEndOffset() < fRange.getEndOffset()) {
136 // add including foreign blocks or split them if needed
137 int lastContainedTlInd = vInd;
138 while (lastContainedTlInd < tlBlocks.size() && fRange.intersectsStrict(tlBlocks.get(lastContainedTlInd).getTextRange())) {
139 lastContainedTlInd++;
141 if (fRange.contains(tlBlocks.get(lastContainedTlInd - 1).getTextRange())) {
144 while (vInd < lastContainedTlInd) {
145 f.addTlChild(tlBlocks.get(vInd++));
149 foreignBlocks.remove(fInd);
150 foreignBlocks.addAll(fInd, buildChildWrappers(f.getOriginal()));
154 while (vInd < tlBlocks.size()) {
155 result.add(tlBlocks.get(vInd++));
157 while (fInd < foreignBlocks.size()) {
158 result.add(foreignBlocks.get(fInd++));
164 public static List<DataLanguageBlockWrapper> filterBlocksByRange(@NotNull List<DataLanguageBlockWrapper> list, @NotNull TextRange textRange) {
166 while (i < list.size()) {
167 final DataLanguageBlockWrapper wrapper = list.get(i);
168 final TextRange range = wrapper.getTextRange();
169 if (textRange.contains(range)) {
172 else if (range.intersectsStrict(textRange)) {
174 list.addAll(i, buildChildWrappers(wrapper.getOriginal()));
183 static List<Block> splitBlockIntoFragments(@NotNull Block block, @NotNull List<TemplateLanguageBlock> subBlocks) {
184 final List<Block> children = new ArrayList<Block>(5);
185 final TextRange range = block.getTextRange();
186 int childStartOffset = range.getStartOffset();
187 TemplateLanguageBlock lastTLBlock = null;
188 for (TemplateLanguageBlock tlBlock : subBlocks) {
189 final TextRange tlTextRange = tlBlock.getTextRange();
190 if (tlTextRange.getStartOffset() > childStartOffset) {
191 TextRange dataBlockTextRange = new TextRange(childStartOffset, tlTextRange.getStartOffset());
192 if (tlBlock.isRequiredRange(dataBlockTextRange)) {
193 children.add(new DataLanguageBlockFragmentWrapper(block, dataBlockTextRange));
196 children.add(tlBlock);
197 lastTLBlock = tlBlock;
198 childStartOffset = tlTextRange.getEndOffset();
200 if (range.getEndOffset() > childStartOffset) {
201 TextRange dataBlockTextRange = new TextRange(childStartOffset, range.getEndOffset());
202 if (lastTLBlock == null || lastTLBlock.isRequiredRange(dataBlockTextRange) ) {
203 children.add(new DataLanguageBlockFragmentWrapper(block, dataBlockTextRange));
209 static void printBlocks(@Nullable TextRange textRange, @NotNull List<Block> list) {
210 StringBuilder sb = new StringBuilder(String.valueOf(textRange)).append(": ");
211 for (Block block : list) {
212 ASTNode node = block instanceof ASTBlock ? ((ASTBlock)block).getNode() : null;
213 TextRange r = block.getTextRange();
214 sb.append(" [").append(node != null ? node.getElementType() : null)//.append(" ").append(((BlockWithParent)block).getParent() != null)
215 .append(r).append(block.getIndent()).append(block.getAlignment()).append("] ");
217 System.out.println(sb);
220 static List<Block> setParent(List<Block> children, BlockWithParent parent) {
221 for (Block block : children) {
222 if (block instanceof BlockWithParent) ((BlockWithParent)block).setParent(parent);