mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Allow to specify ranges which can't be indented by PostprocessReformattingAspect (fixes WI-22725 surround heredoc block with try catch causes parse error) [CR-IC-5135]
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* 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 com.intellij.psi.impl.source;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Used by {@code PostProcessFormattingAspect} to exclude ranges which should never be automatically indented. For example, HEREDOC strings.
|
||||
*
|
||||
* @author Rustam Vishnyakov
|
||||
*/
|
||||
public interface DisabledIndentRangesProvider {
|
||||
ExtensionPointName<DisabledIndentRangesProvider> EP_NAME = ExtensionPointName.create("com.intellij.disabledIndentRangesProvider");
|
||||
|
||||
/**
|
||||
* Collects ranges which should never be indented inside the given PSI element.
|
||||
* @param element The PSI element to check.
|
||||
* @return A collection of ranges with indentation disabled or <i>null</i> if the check is not relevant for the element in question.
|
||||
*/
|
||||
@Nullable
|
||||
Collection<TextRange> getDisabledIndentRanges(@NotNull PsiElement element);
|
||||
}
|
||||
+15
-1
@@ -50,6 +50,7 @@ import com.intellij.psi.impl.source.tree.*;
|
||||
import com.intellij.util.LocalTimeCounter;
|
||||
import com.intellij.util.containers.ContainerUtilRt;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import com.intellij.util.text.TextRangeUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
@@ -536,12 +537,25 @@ public class PostprocessReformattingAspect implements PomModelAspect {
|
||||
final int oldIndent = CodeEditUtil.getOldIndentation(element);
|
||||
CodeEditUtil.setOldIndentation(element, -1);
|
||||
LOG.assertTrue(oldIndent >= 0, "for not generated items old indentation must be defined: element " + element);
|
||||
rangesToProcess.add(new ReindentTask(document.createRangeMarker(element.getTextRange()), oldIndent));
|
||||
for (TextRange indentRange : getEnabledRanges(element.getPsi())) {
|
||||
rangesToProcess.add(new ReindentTask(document.createRangeMarker(indentRange), oldIndent));
|
||||
}
|
||||
inGeneratedContext = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private Iterable<TextRange> getEnabledRanges(@NotNull PsiElement element) {
|
||||
List<TextRange> disabledRanges = new ArrayList<TextRange>();
|
||||
for (DisabledIndentRangesProvider rangesProvider : DisabledIndentRangesProvider.EP_NAME.getExtensions()) {
|
||||
Collection<TextRange> providedDisabledRanges = rangesProvider.getDisabledIndentRanges(element);
|
||||
if (providedDisabledRanges != null) {
|
||||
disabledRanges.addAll(providedDisabledRanges);
|
||||
}
|
||||
}
|
||||
return TextRangeUtil.excludeRanges(element.getTextRange(), disabledRanges);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitComposite(CompositeElement composite) {
|
||||
boolean oldGeneratedContext = inGeneratedContext;
|
||||
|
||||
@@ -262,6 +262,7 @@
|
||||
<extensionPoint name="elementSignatureProvider" interface="com.intellij.codeInsight.folding.impl.ElementSignatureProvider"/>
|
||||
<extensionPoint name="preFormatProcessor" interface="com.intellij.psi.impl.source.codeStyle.PreFormatProcessor"/>
|
||||
<extensionPoint name="postFormatProcessor" interface="com.intellij.psi.impl.source.codeStyle.PostFormatProcessor"/>
|
||||
<extensionPoint name="disabledIndentRangesProvider" interface="com.intellij.psi.impl.source.DisabledIndentRangesProvider"/>
|
||||
|
||||
<extensionPoint name="declarationRangeHandler" beanClass="com.intellij.util.MixinEP">
|
||||
<with attribute="implementationClass" implements="com.intellij.codeInsight.hint.DeclarationRangeHandler"/>
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* 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 com.intellij.util.text;
|
||||
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Rustam Vishnyakov
|
||||
*/
|
||||
public class TextRangeUtil {
|
||||
|
||||
private final static Comparator<TextRange> RANGE_COMPARATOR = new Comparator<TextRange>() {
|
||||
@Override
|
||||
public int compare(TextRange range1, TextRange range2) {
|
||||
int startOffsetDiff = range1.getStartOffset() - range2.getStartOffset();
|
||||
return startOffsetDiff != 0 ? startOffsetDiff : range1.getEndOffset() - range2.getEndOffset();
|
||||
}
|
||||
};
|
||||
|
||||
private TextRangeUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Excludes ranges from the original range. For example, if the original range is [30..100] and ranges to exclude are
|
||||
* [20..50] and [60..90], resulting ranges will be [50..60] and [90..100]. The ranges may overlap and follow in any order. In the latter
|
||||
* case the original list of excluded ranges is sorted by start/end offset.
|
||||
*
|
||||
* @param original The original range to exclude the ranges from.
|
||||
* @param excludedRanges The list of ranges to exclude.
|
||||
* @return A list of ranges after excluded ranges have been applied.
|
||||
*/
|
||||
public static Iterable<TextRange> excludeRanges(@NotNull TextRange original, @NotNull List<TextRange> excludedRanges) {
|
||||
if (!excludedRanges.isEmpty()) {
|
||||
List<TextRange> enabledRanges = new ArrayList<TextRange>();
|
||||
if (excludedRanges.size() > 1) {
|
||||
Collections.sort(excludedRanges, RANGE_COMPARATOR);
|
||||
}
|
||||
int enabledRangeStart = original.getStartOffset();
|
||||
for (TextRange excludedRange : excludedRanges) {
|
||||
if (excludedRange.getEndOffset() < enabledRangeStart) continue;
|
||||
int excludedRangeStart = excludedRange.getStartOffset();
|
||||
if (excludedRangeStart > original.getEndOffset()) break;
|
||||
if (excludedRangeStart > enabledRangeStart) {
|
||||
enabledRanges.add(new TextRange(enabledRangeStart, excludedRangeStart));
|
||||
}
|
||||
enabledRangeStart = excludedRange.getEndOffset();
|
||||
}
|
||||
if (enabledRangeStart < original.getEndOffset()) {
|
||||
enabledRanges.add(new TextRange(enabledRangeStart, original.getEndOffset()));
|
||||
}
|
||||
return enabledRanges;
|
||||
}
|
||||
return Arrays.asList(original);
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,13 @@
|
||||
|
||||
package com.intellij.openapi.util;
|
||||
|
||||
import com.intellij.util.text.TextRangeUtil;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author dyoma
|
||||
*/
|
||||
@@ -56,4 +61,32 @@ public class TextRangeTest extends TestCase {
|
||||
assertEquals("0345", range.replace("012345", ""));
|
||||
assertEquals("0abcdef345", range.replace("012345", "abcdef"));
|
||||
}
|
||||
|
||||
public void testExcludedRanges() {
|
||||
List<TextRange> excludedRanges =
|
||||
Arrays.asList(
|
||||
new TextRange(95,110),
|
||||
new TextRange(15,40),
|
||||
new TextRange(5,20),
|
||||
new TextRange(105,120),
|
||||
new TextRange(70,90),
|
||||
new TextRange(50,57),
|
||||
new TextRange(56,65),
|
||||
new TextRange(50,60)
|
||||
);
|
||||
List<TextRange> expectedRanges =
|
||||
Arrays.asList(
|
||||
new TextRange(40,50),
|
||||
new TextRange(65,70),
|
||||
new TextRange(90,95)
|
||||
);
|
||||
Iterable<TextRange> result = TextRangeUtil.excludeRanges(new TextRange(30,100), excludedRanges);
|
||||
Iterator<TextRange> resultIterator = result.iterator();
|
||||
for (TextRange expectedRange : expectedRanges) {
|
||||
assertTrue("Less elements than expected", resultIterator.hasNext());
|
||||
TextRange actualRange = resultIterator.next();
|
||||
assertEquals("Ranges do not match", expectedRange, actualRange);
|
||||
}
|
||||
assertTrue("More elements than expected", !resultIterator.hasNext());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user