Merge remote-tracking branch 'origin/master'

This commit is contained in:
Konstantin Bulenkov
2015-10-02 18:59:30 +02:00
94 changed files with 1911 additions and 858 deletions
+4 -4
View File
@@ -37,10 +37,10 @@ TR=`which tr`
#Disbale Jayatana on linux
#if [ -n "$JAVA_TOOL_OPTIONS" ]; then
# JAVA_TOOL_OPTIONS=${JAVA_TOOL_OPTIONS%-javaagent*jayatanaag.jar*}${JAVA_TOOL_OPTIONS#*jayatanaag.jar}
# message "Jayatana global menu integration is disabled."
#fi
if [ -n "$JAVA_TOOL_OPTIONS" ]; then
JAVA_TOOL_OPTIONS=${JAVA_TOOL_OPTIONS%-javaagent*jayatanaag.jar*}${JAVA_TOOL_OPTIONS#*jayatanaag.jar}
message "Jayatana global menu integration is disabled."
fi
if [ -z "$UNAME" -o -z "$GREP" -o -z "$CUT" -o -z "$MKTEMP" -o -z "$RM" -o -z "$CAT" -o -z "$TR" ]; then
message "Required tools are missing - check beginning of \"$0\" file for details."
Binary file not shown.
@@ -309,22 +309,37 @@ public class LocalVariablesUtil {
private int myCurrentSlotIndex;
private final PsiElement myElement;
private final Stack<Integer> myIndexStack;
private boolean myReached = false;
public LocalVariableNameFinder(int startSlot, MultiMap<Integer, String> names, PsiElement element) {
myNames = names;
myCurrentSlotIndex = startSlot;
myElement = element;
myIndexStack = new Stack<Integer>();
}
private boolean shouldVisit(PsiElement scope) {
return PsiTreeUtil.isContextAncestor(scope, myElement, false);
return !myReached && PsiTreeUtil.isContextAncestor(scope, myElement, false);
}
@Override
public void visitElement(PsiElement element) {
if (element == myElement) {
myReached = true;
}
else {
super.visitElement(element);
}
}
@Override
public void visitLocalVariable(PsiLocalVariable variable) {
appendName(variable.getName());
myCurrentSlotIndex += getTypeSlotSize(variable.getType());
super.visitLocalVariable(variable);
if (!myReached) {
appendName(variable.getName());
myCurrentSlotIndex += getTypeSlotSize(variable.getType());
}
}
public void visitSynchronizedStatement(PsiSynchronizedStatement statement) {
@@ -258,7 +258,9 @@ public class JrePathEditor extends JPanel implements PanelWithAnchor {
@Override
public void render(SimpleColoredComponent component, boolean selected) {
component.append(DEFAULT_JRE_TEXT);
component.append(myDefaultJreSelector.getDescriptionString(), SimpleTextAttributes.GRAY_ATTRIBUTES);
if (myDefaultJreSelector != null) {
component.append(myDefaultJreSelector.getDescriptionString(), SimpleTextAttributes.GRAY_ATTRIBUTES);
}
}
@Override
@@ -216,6 +216,7 @@ public class JavaCompletionContributor extends CompletionContributor {
if (ANNOTATION_ATTRIBUTE_NAME.accepts(position) && !JavaKeywordCompletion.isAfterPrimitiveOrArrayType(position)) {
JavaKeywordCompletion.addExpectedTypeMembers(parameters, result);
JavaKeywordCompletion.addPrimitiveTypes(result, position);
completeAnnotationAttributeName(result, position, parameters);
result.stopHere();
return;
@@ -22,6 +22,7 @@ import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler;
import com.intellij.codeInsight.daemon.impl.analysis.LambdaHighlightingUtil;
import com.intellij.codeInsight.lookup.*;
import com.intellij.openapi.util.AtomicNotNullLazyValue;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.patterns.ElementPattern;
import com.intellij.pom.java.LanguageLevel;
@@ -32,10 +33,12 @@ import com.intellij.psi.filters.position.*;
import com.intellij.psi.impl.source.jsp.jspJava.JspClassLevelDeclarationStatement;
import com.intellij.psi.jsp.JspElementType;
import com.intellij.psi.templateLanguages.OuterLanguageElement;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.Consumer;
import com.intellij.util.ProcessingContext;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -578,8 +581,9 @@ public class JavaKeywordCompletion {
isAfterPrimitiveOrArrayType(position);
}
private static void addPrimitiveTypes(final Consumer<LookupElement> result, PsiElement position) {
if (AFTER_DOT.accepts(position)) {
static void addPrimitiveTypes(final Consumer<LookupElement> result, PsiElement position) {
if (AFTER_DOT.accepts(position) ||
psiElement().inside(psiAnnotation()).accepts(position) && !expectsClassLiteral(position)) {
return;
}
@@ -623,6 +627,15 @@ public class JavaKeywordCompletion {
}
}
private static boolean expectsClassLiteral(PsiElement position) {
return ContainerUtil.find(JavaSmartCompletionContributor.getExpectedTypes(position, false), new Condition<ExpectedTypeInfo>() {
@Override
public boolean value(ExpectedTypeInfo info) {
return InheritanceUtil.isInheritor(info.getType(), CommonClassNames.JAVA_LANG_CLASS);
}
}) != null;
}
private static boolean isAtResourceVariableStart(PsiElement position) {
return psiElement().insideStarting(psiElement(PsiTypeElement.class).withParent(PsiResourceList.class)).accepts(position);
}
@@ -246,12 +246,11 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
@NotNull
public static ExpectedTypeInfo[] getExpectedTypes(final CompletionParameters parameters) {
return getExpectedTypes(parameters, parameters.getCompletionType() == CompletionType.SMART);
return getExpectedTypes(parameters.getPosition(), parameters.getCompletionType() == CompletionType.SMART);
}
@NotNull
public static ExpectedTypeInfo[] getExpectedTypes(final CompletionParameters parameters, boolean voidable) {
final PsiElement position = parameters.getPosition();
public static ExpectedTypeInfo[] getExpectedTypes(PsiElement position, boolean voidable) {
if (psiElement().withParent(psiElement(PsiReferenceExpression.class).withParent(PsiThrowStatement.class)).accepts(position)) {
final PsiElementFactory factory = JavaPsiFacade.getInstance(position.getProject()).getElementFactory();
final PsiClassType classType = factory
@@ -45,7 +45,7 @@ public class MagicCompletionContributor extends CompletionContributor {
private static final ElementPattern<PsiElement> IN_METHOD_CALL_ARGUMENT =
psiElement().withParent(psiElement(PsiReferenceExpression.class).inside(psiElement(PsiExpressionList.class).withParent(PsiCall.class)));
private static final ElementPattern<PsiElement> IN_BINARY_COMPARISON =
psiElement().withParent(psiElement(PsiReferenceExpression.class).inside(psiElement(PsiBinaryExpression.class)));
psiElement().withParent(psiElement(PsiReferenceExpression.class).inside(psiElement(PsiPolyadicExpression.class)));
private static final ElementPattern<PsiElement> IN_ASSIGNMENT =
psiElement().withParent(psiElement(PsiReferenceExpression.class).inside(psiElement(PsiAssignmentExpression.class)));
private static final ElementPattern<PsiElement> IN_RETURN =
@@ -129,17 +129,13 @@ public class MagicCompletionContributor extends CompletionContributor {
}
}
else if (IN_BINARY_COMPARISON.accepts(pos)) {
PsiBinaryExpression exp = PsiTreeUtil.getParentOfType(pos, PsiBinaryExpression.class);
PsiPolyadicExpression exp = PsiTreeUtil.getParentOfType(pos, PsiPolyadicExpression.class);
if (exp != null && (exp.getOperationTokenType() == JavaTokenType.EQEQ || exp.getOperationTokenType() == JavaTokenType.NE)) {
PsiExpression l = exp.getLOperand();
PsiModifierListOwner resolved = resolveExpression(l);
if (resolved != null) {
result.add(Pair.create(resolved, l.getType()));
}
PsiExpression r = exp.getROperand();
resolved = resolveExpression(r);
if (r != null && resolved != null) {
result.add(Pair.create(resolved, r.getType()));
for (PsiExpression operand : exp.getOperands()) {
PsiModifierListOwner resolved = resolveExpression(operand);
if (resolved != null) {
result.add(Pair.create(resolved, operand.getType()));
}
}
}
}
@@ -49,7 +49,7 @@ public class CommentFormatter {
public CommentFormatter(@NotNull Project project) {
mySettings = CodeStyleSettingsManager.getSettings(project);
myParser = new JDParser(mySettings, LanguageLevelProjectExtension.getInstance(project).getLanguageLevel());
myParser = new JDParser(mySettings);
myProject = project;
}
@@ -45,11 +45,9 @@ public class JDParser {
private static final char lineSeparator = '\n';
private final CodeStyleSettings mySettings;
private final LanguageLevel myLanguageLevel;
public JDParser(@NotNull CodeStyleSettings settings, @NotNull LanguageLevel languageLevel) {
public JDParser(@NotNull CodeStyleSettings settings) {
mySettings = settings;
myLanguageLevel = languageLevel;
}
public void formatCommentText(@NotNull PsiElement element, @NotNull CommentFormatter formatter) {
@@ -253,7 +251,7 @@ public class JDParser {
first = true;
if (p2nl) {
if (isParaTag(token) && s.indexOf(P_END_TAG, curPos) < 0) {
list.add("");
list.add(isSelfClosedPTag(token) ? SELF_CLOSED_P_TAG : "");
markers.add(Boolean.valueOf(preCount > 0));
continue;
}
@@ -277,6 +275,11 @@ public class JDParser {
String withoutWS = removeWhiteSpacesFrom(token).toLowerCase();
return withoutWS.equals(SELF_CLOSED_P_TAG) || withoutWS.equals(P_START_TAG);
}
private static boolean isSelfClosedPTag(@NotNull final String token) {
return removeWhiteSpacesFrom(token).toLowerCase().equals(SELF_CLOSED_P_TAG);
}
@NotNull
private static String removeWhiteSpacesFrom(@NotNull final String token) {
@@ -379,12 +382,12 @@ public class JDParser {
result.add(Pair.create(s1, marks[i]));
}
else {
if (s1.isEmpty()) {
if (s1.isEmpty() || s1.equals(SELF_CLOSED_P_TAG)) {
if (sb.length() != 0) {
result.add(new Pair<String, Boolean>(sb.toString(), false));
sb.setLength(0);
}
result.add(Pair.create("", marks[i]));
result.add(Pair.create(s1, marks[i]));
}
else if (mySettings.JD_PRESERVE_LINE_FEEDS) {
result.add(Pair.create(s1, marks[i]));
@@ -596,13 +599,7 @@ public class JDParser {
if (line.isEmpty() && !mySettings.JD_KEEP_EMPTY_LINES) continue;
if (i != 0) sb.append(prefix);
if (line.isEmpty() && mySettings.JD_P_AT_EMPTY_LINES && !insidePreTag) {
if (myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8)) {
//Self-closing elements are not allowed for javadoc tool from JDK8
sb.append(P_START_TAG);
}
else {
sb.append(SELF_CLOSED_P_TAG);
}
sb.append(P_START_TAG);
}
else {
sb.append(line);
@@ -88,6 +88,7 @@ public class TypeEvaluator {
e.addFirst(type);
usageInfo.setOwnerRoot(myLabeler.getCurrentRoot());
myTypeMap.put(usageInfo, e);
return true;
}
@@ -23,6 +23,7 @@ import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiDiamondTypeUtil;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.javadoc.PsiDocTagValue;
import com.intellij.psi.search.PsiSearchScopeUtil;
@@ -36,13 +37,21 @@ import com.intellij.refactoring.typeMigration.usageInfo.OverridenUsageInfo;
import com.intellij.refactoring.typeMigration.usageInfo.OverriderUsageInfo;
import com.intellij.refactoring.typeMigration.usageInfo.TypeMigrationUsageInfo;
import com.intellij.usageView.UsageInfo;
import com.intellij.util.Consumer;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.Query;
import com.intellij.util.containers.*;
import com.intellij.util.graph.DFSTBuilder;
import com.intellij.util.graph.GraphGenerator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import javax.swing.*;
import java.util.*;
import java.util.HashMap;
import java.util.HashSet;
/**
* @author db
@@ -132,15 +141,8 @@ public class TypeMigrationLabeler {
int j = 0;
List<PsiElement> conversionExprs = new ArrayList<PsiElement>(myConversions.keySet());
Collections.sort(conversionExprs, new Comparator<PsiElement>() {
public int compare(final PsiElement e1, final PsiElement e2) {
return e2.getTextRange().getStartOffset() - e1.getTextRange().getStartOffset();
}
});
for (final PsiElement element : conversionExprs) {
for (final PsiElement element : myConversions.keySet()) {
final Object conv = myConversions.get(element);
usages[j++] = new TypeMigrationUsageInfo(element) {
public String getTooltipText() {
if (conv instanceof String) { //todo
@@ -157,6 +159,11 @@ public class TypeMigrationLabeler {
if (conv instanceof TypeConversionDescriptorBase) return ((TypeConversionDescriptorBase)conv).getRoot().isExcluded();
return super.isExcluded();
}
@Override
public TypeMigrationUsageInfo getOwnerRoot() {
return conv instanceof TypeConversionDescriptorBase ? ((TypeConversionDescriptorBase)conv).getRoot() : null;
}
};
}
@@ -172,10 +179,76 @@ public class TypeMigrationLabeler {
for (final TypeMigrationUsageInfo expr : myNewExpressionTypeChange.keySet()) {
usages[j++] = expr;
}
return usages;
return sortMigratedUsages(usages);
}
public void change(final TypeMigrationUsageInfo usageInfo) {
private TypeMigrationUsageInfo[] sortMigratedUsages(TypeMigrationUsageInfo[] infos) {
final DFSTBuilder<TypeMigrationUsageInfo> builder = new DFSTBuilder<TypeMigrationUsageInfo>(GraphGenerator.create(
new GraphGenerator.SemiGraph<TypeMigrationUsageInfo>() {
@Override
public Collection<TypeMigrationUsageInfo> getNodes() {
final Set<TypeMigrationUsageInfo> infos = new HashSet<TypeMigrationUsageInfo>();
for (Map.Entry<TypeMigrationUsageInfo, HashSet<Pair<TypeMigrationUsageInfo, PsiType>>> entry : myRootsTree.entrySet()) {
infos.add(entry.getKey());
infos.addAll(ContainerUtil.map(entry.getValue(), new Function<Pair<TypeMigrationUsageInfo, PsiType>, TypeMigrationUsageInfo>() {
@Override
public TypeMigrationUsageInfo fun(Pair<TypeMigrationUsageInfo, PsiType> pair) {
return pair.getFirst();
}
}));
}
return infos;
}
@Override
public Iterator<TypeMigrationUsageInfo> getIn(TypeMigrationUsageInfo n) {
final HashSet<Pair<TypeMigrationUsageInfo, PsiType>> rawNodes = myRootsTree.get(n);
if (rawNodes == null) {
return Collections.<TypeMigrationUsageInfo>emptyList().iterator();
}
final List<TypeMigrationUsageInfo> in =
ContainerUtil.map(rawNodes, new Function<Pair<TypeMigrationUsageInfo, PsiType>, TypeMigrationUsageInfo>() {
@Override
public TypeMigrationUsageInfo fun(Pair<TypeMigrationUsageInfo, PsiType> pair) {
return pair.getFirst();
}
});
return in.iterator();
}
}));
final Comparator<TypeMigrationUsageInfo> cmp = builder.comparator();
Arrays.sort(infos, new Comparator<TypeMigrationUsageInfo>() {
@Override
public int compare(final TypeMigrationUsageInfo info1, final TypeMigrationUsageInfo info2) {
final TypeMigrationUsageInfo i1 = info1.getOwnerRoot();
final TypeMigrationUsageInfo i2 = info2.getOwnerRoot();
if (i1 == null && i2 == null) {
return 0;
}
if (i1 == null) {
return 1;
}
if (i2 == null) {
return -1;
}
final int res = cmp.compare(i1, i2);
if (res != 0) {
return res;
}
final PsiElement element1 = info1.getElement();
final PsiElement element2 = info2.getElement();
LOG.assertTrue(element1 != null && element2 != null);
return element2.getTextRange().getStartOffset() - element1.getTextRange().getStartOffset();
}
});
return infos;
}
public void change(final TypeMigrationUsageInfo usageInfo, @NotNull Consumer<PsiNewExpression> consumer) {
final PsiElement element = usageInfo.getElement();
if (element == null) return;
final Project project = element.getProject();
@@ -185,7 +258,11 @@ public class TypeMigrationLabeler {
for (Map.Entry<TypeMigrationUsageInfo, PsiType> info : myNewExpressionTypeChange.entrySet()) {
final PsiElement expressionToReplace = info.getKey().getElement();
if (expression.equals(expressionToReplace)) {
TypeMigrationReplacementUtil.replaceNewExpressionType(project, (PsiNewExpression)expressionToReplace, info);
final PsiNewExpression newExpression =
TypeMigrationReplacementUtil.replaceNewExpressionType(project, (PsiNewExpression)expressionToReplace, info);
if (newExpression != null) {
consumer.consume(newExpression);
}
}
}
}
@@ -212,6 +289,10 @@ public class TypeMigrationLabeler {
}
}
void postProcessNewExpression(@NotNull PsiNewExpression expression) {
TypeMigrationReplacementUtil.tryToReplaceWithDiamond(expression, null);
}
@Nullable
Object getConversion(PsiElement element) {
return myConversions.get(element);
@@ -310,7 +391,9 @@ public class TypeMigrationLabeler {
return;
}
myNewExpressionTypeChange.put(new TypeMigrationUsageInfo(expr), migrationType);
final TypeMigrationUsageInfo usageInfo = new TypeMigrationUsageInfo(expr);
usageInfo.setOwnerRoot(myCurrentRoot);
myNewExpressionTypeChange.put(usageInfo, migrationType);
getTypeEvaluator().setType(new TypeMigrationUsageInfo(expr), migrationType);
return;
} else {
@@ -322,7 +405,9 @@ public class TypeMigrationLabeler {
final PsiType type = TypeEvaluator.substituteType(migrationType, originalType, true, ((PsiClassType)originalType).resolveGenerics().getElement(),
JavaPsiFacade.getElementFactory(expr.getProject()).createType(((PsiClassType)originalType).resolve(), PsiSubstitutor.EMPTY));
if (type != null){
myNewExpressionTypeChange.put(new TypeMigrationUsageInfo(expr), type);
final TypeMigrationUsageInfo usageInfo = new TypeMigrationUsageInfo(expr);
usageInfo.setOwnerRoot(myCurrentRoot);
myNewExpressionTypeChange.put(usageInfo, type);
getTypeEvaluator().setType(new TypeMigrationUsageInfo(expr), type);
return;
}
@@ -384,9 +469,6 @@ public class TypeMigrationLabeler {
return false;
}
//TODO dmitry batkovich
//type = JavaPsiFacade.getElementFactory(element.getProject()).createTypeFromText(type.getCanonicalText(true), element);
if (resolved instanceof PsiMethod) {
final PsiMethod method = ((PsiMethod)resolved);
final PsiMethod[] methods = OverridingMethodsSearch.search(method, true).toArray(PsiMethod.EMPTY_ARRAY);
@@ -610,18 +692,24 @@ public class TypeMigrationLabeler {
return validReferences.toArray(new PsiReference[validReferences.size()]);
}
public void migrateRoot(final PsiElement root, final PsiType migrationType, final PsiReference[] usages) {
public void setRootAndMigrate(final TypeMigrationUsageInfo newRootUsageInfo, final PsiType migrationType, final PsiReference[] usages) {
final TypeMigrationUsageInfo oldRoot = getCurrentRoot();
setCurrentRoot(newRootUsageInfo);
PsiElement root = newRootUsageInfo.getElement();
if (root instanceof PsiMethod) {
migrateMethodReturnExpression(migrationType, (PsiMethod)root);
}
else if (root instanceof PsiParameter && ((PsiParameter)root).getDeclarationScope() instanceof PsiMethod) {
migrateMethodCallExpressions(migrationType, (PsiParameter)root, null);
}
else if (root instanceof PsiVariable || root instanceof PsiExpression){
else if (root instanceof PsiVariable || root instanceof PsiExpression) {
final PsiElement element = getContainingStatement(root);
element.accept(new TypeMigrationStatementProcessor(element, this));
} else if (root instanceof PsiReferenceParameterList) {
myClassTypeArgumentsChange.put(new TypeMigrationUsageInfo(root), (PsiClassType)migrationType);
}
else if (root instanceof PsiReferenceParameterList) {
final TypeMigrationUsageInfo info = new TypeMigrationUsageInfo(root);
info.setOwnerRoot(oldRoot);
myClassTypeArgumentsChange.put(info, (PsiClassType)migrationType);
new ClassTypeArgumentMigrationProcessor(this).migrateClassTypeParameter((PsiReferenceParameterList)root, migrationType);
}
@@ -726,8 +814,7 @@ public class TypeMigrationLabeler {
j = 0;
for (final Pair<TypeMigrationUsageInfo, PsiType> root : roots) {
myCurrentRoot = root.getFirst();
migrateRoot(root.getFirst().getElement(), root.getSecond(), cachedUsages[j++]);
setRootAndMigrate(root.getFirst(), root.getSecond(), cachedUsages[j++]);
}
}
@@ -760,6 +847,10 @@ public class TypeMigrationLabeler {
myCurrentRoot = currentRoot;
}
TypeMigrationUsageInfo getCurrentRoot() {
return myCurrentRoot;
}
public LinkedList<Pair<TypeMigrationUsageInfo, PsiType>> getMigrationRoots() {
return myMigrationRoots;
}
@@ -33,7 +33,9 @@ import com.intellij.ui.content.Content;
import com.intellij.usageView.UsageInfo;
import com.intellij.usageView.UsageViewDescriptor;
import com.intellij.usageView.UsageViewManager;
import com.intellij.util.Consumer;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@@ -180,6 +182,8 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor {
}
public static void change(TypeMigrationLabeler labeler, UsageInfo[] usages) {
final List<PsiNewExpression> newExpressionsToCheckDiamonds = new SmartList<PsiNewExpression>();
List<UsageInfo> nonCodeUsages = new ArrayList<UsageInfo>();
for (UsageInfo usage : usages) {
if (((TypeMigrationUsageInfo)usage).isExcluded()) continue;
@@ -188,12 +192,22 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor {
element instanceof PsiMember ||
element instanceof PsiExpression ||
element instanceof PsiReferenceParameterList) {
labeler.change((TypeMigrationUsageInfo)usage);
labeler.change((TypeMigrationUsageInfo)usage, new Consumer<PsiNewExpression>() {
@Override
public void consume(@NotNull PsiNewExpression expression) {
newExpressionsToCheckDiamonds.add(expression);
}
});
}
else {
nonCodeUsages.add(usage);
}
}
for (PsiNewExpression newExpression : newExpressionsToCheckDiamonds) {
labeler.postProcessNewExpression(newExpression);
}
for (UsageInfo usageInfo : nonCodeUsages) {
final PsiElement element = usageInfo.getElement();
if (element != null) {
@@ -25,6 +25,7 @@ import com.intellij.psi.impl.source.tree.CompositeElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.typeMigration.usageInfo.TypeMigrationUsageInfo;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
@@ -138,7 +139,7 @@ public class TypeMigrationReplacementUtil {
}
}
static void replaceNewExpressionType(final Project project, final PsiNewExpression expression, final Map.Entry<TypeMigrationUsageInfo, PsiType> info) {
static PsiNewExpression replaceNewExpressionType(final Project project, final PsiNewExpression expression, final Map.Entry<TypeMigrationUsageInfo, PsiType> info) {
final PsiType changeType = info.getValue();
if (changeType != null) {
try {
@@ -147,11 +148,8 @@ public class TypeMigrationReplacementUtil {
if (classReference != null) {
final PsiElement psiElement = replaceTypeWithClassReferenceOrKeyword(project, componentType, classReference);
final PsiNewExpression newExpression = PsiTreeUtil.getParentOfType(psiElement, PsiNewExpression.class);
if (newExpression != null && PsiDiamondTypeUtil.canCollapseToDiamond(newExpression, newExpression, changeType)) {
final PsiJavaCodeReferenceElement anonymousClassReference = newExpression.getClassOrAnonymousClassReference();
if (anonymousClassReference != null) {
PsiDiamondTypeUtil.replaceExplicitWithDiamond(anonymousClassReference.getParameterList());
}
if (!tryToReplaceWithDiamond(newExpression, changeType)) {
return newExpression;
}
}
else {
@@ -165,6 +163,18 @@ public class TypeMigrationReplacementUtil {
LOG.error(e);
}
}
return null;
}
static boolean tryToReplaceWithDiamond(PsiNewExpression newExpression, @Nullable PsiType changeType) {
if (newExpression != null && PsiDiamondTypeUtil.canCollapseToDiamond(newExpression, newExpression, changeType)) {
final PsiJavaCodeReferenceElement anonymousClassReference = newExpression.getClassOrAnonymousClassReference();
if (anonymousClassReference != null) {
PsiDiamondTypeUtil.replaceExplicitWithDiamond(anonymousClassReference.getParameterList());
}
return true;
}
return false;
}
private static PsiElement replaceTypeWithClassReferenceOrKeyword(Project project, PsiType componentType, PsiElement typePlace) {
@@ -81,10 +81,8 @@ public class MigrationNode extends AbstractTreeNode<TypeMigrationUsageInfo> impl
final PsiElement element = myInfo.getElement();
if (element != null) {
myLabeler.setCurrentRoot(myInfo);
try {
myLabeler.migrateRoot(element, myMigrationType, myLabeler.markRootUsages(element, myMigrationType));
myLabeler.setRootAndMigrate(myInfo, myMigrationType, myLabeler.markRootUsages(element, myMigrationType));
}
catch (TypeMigrationLabeler.MigrateException e) {
//skip warning
@@ -18,6 +18,7 @@ package com.intellij.refactoring.typeMigration.usageInfo;
import com.intellij.psi.PsiElement;
import com.intellij.usageView.UsageInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author anna
@@ -25,6 +26,7 @@ import org.jetbrains.annotations.NotNull;
*/
public class TypeMigrationUsageInfo extends UsageInfo {
private boolean myExcluded;
private TypeMigrationUsageInfo myOwnerRoot;
public TypeMigrationUsageInfo(@NotNull PsiElement element) {
@@ -39,4 +41,16 @@ public class TypeMigrationUsageInfo extends UsageInfo {
return myExcluded;
}
public TypeMigrationUsageInfo getOwnerRoot() {
return myOwnerRoot;
}
public void setOwnerRoot(TypeMigrationUsageInfo ownerRoot) {
myOwnerRoot = ownerRoot;
}
@Override
public String toString() {
return getClass().getSimpleName() + ":" + getElement();
}
}
@@ -19,7 +19,6 @@ import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.icons.AllIcons;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
@@ -54,7 +53,6 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.intellij.util.containers.ContainerUtil.ar;
@@ -93,18 +91,21 @@ public class UnscrambleDialog extends DialogWrapper {
populateRegisteredUnscramblerList();
myUnscrambleChooser.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
UnscrambleSupport unscrambleSupport = getSelectedUnscrambler();
GuiUtils.enableChildren(myLogFileChooserPanel, unscrambleSupport != null);
}
});
myUseUnscrambler.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
useUnscramblerChanged();
}
});
myOnTheFly.setSelected(Registry.get("analyze.exceptions.on.the.fly").asBoolean());
myOnTheFly.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Registry.get("analyze.exceptions.on.the.fly").setValue(myOnTheFly.isSelected());
}
@@ -172,10 +173,9 @@ public class UnscrambleDialog extends DialogWrapper {
@Nullable
private UnscrambleSupport getSavedUnscrambler() {
final List<UnscrambleSupport> registeredUnscramblers = getRegisteredUnscramblers();
final String savedUnscramblerName = getPropertyValue(PROPERTY_UNSCRAMBLER_NAME_USED);
UnscrambleSupport selectedUnscrambler = null;
for (final UnscrambleSupport unscrambleSupport : registeredUnscramblers) {
for (UnscrambleSupport unscrambleSupport : UnscrambleSupport.EP_NAME.getExtensions()) {
if (Comparing.strEqual(unscrambleSupport.getPresentableName(), savedUnscramblerName)) {
selectedUnscrambler = unscrambleSupport;
}
@@ -206,11 +206,13 @@ public class UnscrambleDialog extends DialogWrapper {
myEditorPanel.add(myStacktraceEditorPanel, BorderLayout.CENTER);
}
@Override
@NotNull
protected Action[] createActions(){
return new Action[]{createNormalizeTextAction(), getOKAction(), getCancelAction(), getHelpAction()};
}
@Override
public JComponent getPreferredFocusedComponent() {
JRootPane pane = getRootPane();
return pane != null ? pane.getDefaultButton() : super.getPreferredFocusedComponent();
@@ -219,6 +221,7 @@ public class UnscrambleDialog extends DialogWrapper {
private void createLogFileChooser() {
myLogFile = new TextFieldWithHistory();
JPanel panel = GuiUtils.constructFieldWithBrowseButton(myLogFile, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor();
FileChooser.chooseFiles(descriptor, myProject, null, new Consumer<List<VirtualFile>>() {
@@ -234,10 +237,11 @@ public class UnscrambleDialog extends DialogWrapper {
}
private void populateRegisteredUnscramblerList() {
List<UnscrambleSupport> unscrambleComponents = getRegisteredUnscramblers();
for (final UnscrambleSupport unscrambleSupport : unscrambleComponents) {
for (UnscrambleSupport unscrambleSupport : UnscrambleSupport.EP_NAME.getExtensions()) {
//noinspection unchecked
myUnscrambleChooser.addItem(unscrambleSupport);
}
//noinspection unchecked
myUnscrambleChooser.setRenderer(new ListCellRendererWrapper<UnscrambleSupport>() {
@Override
public void customize(JList list, UnscrambleSupport unscrambleSupport, int index, boolean selected, boolean hasFocus) {
@@ -246,26 +250,29 @@ public class UnscrambleDialog extends DialogWrapper {
});
}
private static List<UnscrambleSupport> getRegisteredUnscramblers() {
final UnscrambleSupport[] components = Extensions.getExtensions(UnscrambleSupport.EP_NAME);
return Arrays.asList(components);
}
@Override
protected JComponent createCenterPanel() {
return myPanel;
}
@Override
public void dispose() {
if (isOK()){
final List<String> list = myLogFile.getHistory();
PropertiesComponent.getInstance().setValue(PROPERTY_LOG_FILE_HISTORY_URLS, list.isEmpty() ? null : StringUtil.join(list, ":::"), null);
UnscrambleSupport selectedUnscrambler = getSelectedUnscrambler();
PropertiesComponent.getInstance().setValue(PROPERTY_UNSCRAMBLER_NAME_USED, selectedUnscrambler == null ? null : selectedUnscrambler.getPresentableName(), null);
PropertiesComponent.getInstance().setValue(PROPERTY_LOG_FILE_LAST_URL, StringUtil.nullize(myLogFile.getText()), null);
saveProperty(PROPERTY_UNSCRAMBLER_NAME_USED, selectedUnscrambler == null ? null : selectedUnscrambler.getPresentableName());
saveProperty(PROPERTY_LOG_FILE_LAST_URL, StringUtil.nullize(myLogFile.getText()));
}
super.dispose();
}
// IDEA-125302 The Analyze Stacktrace menu option remembers only one log file across multiple projects
private void saveProperty(@NotNull String name, @Nullable String value) {
PropertiesComponent.getInstance(myProject).setValue(name, value);
PropertiesComponent.getInstance().setValue(name, value);
}
@Nullable
private String getPropertyValue(@NotNull String name) {
String projectValue = PropertiesComponent.getInstance(myProject).getValue(name);
@@ -289,6 +296,7 @@ public class UnscrambleDialog extends DialogWrapper {
putValue(DEFAULT_ACTION, Boolean.FALSE);
}
@Override
public void actionPerformed(ActionEvent e){
String text = myStacktraceEditorPanel.getText();
myStacktraceEditorPanel.setText(normalizeText(text));
@@ -366,6 +374,7 @@ public class UnscrambleDialog extends DialogWrapper {
return false;
}
@Override
protected void doOKAction() {
if (myConfigurable != null && myConfigurable.isModified()) {
try {
@@ -382,6 +391,7 @@ public class UnscrambleDialog extends DialogWrapper {
}
}
@Override
public void doHelpAction() {
HelpManager.getInstance().invokeHelp("find.analyzeStackTrace");
}
@@ -423,6 +433,7 @@ public class UnscrambleDialog extends DialogWrapper {
return AnalyzeStacktraceUtil.addConsole(project, threadDump.size() > 1 ? new ThreadDumpConsoleFactory(project, threadDump) : null, message, unscrambledTrace, icon);
}
@Override
protected String getDimensionServiceKey(){
return "#com.intellij.unscramble.UnscrambleDialog";
}
@@ -474,5 +485,4 @@ public class UnscrambleDialog extends DialogWrapper {
}
return builder.toString();
}
}
@@ -160,6 +160,6 @@ public class StrictSubtypingConstraint implements ConstraintFormula {
@Override
public String toString() {
return myS.getPresentableText() + " < " + myT.getPresentableText();
return myT.getPresentableText() + " < " + myS.getPresentableText();
}
}
@@ -24,6 +24,7 @@ import com.intellij.openapi.util.Computable;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiSuperMethodImplUtil;
import com.intellij.psi.impl.source.PsiImmediateClassType;
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.infos.MethodCandidateInfo;
@@ -687,26 +688,29 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
private boolean isApplicableTo(@NotNull PsiType[] types2AtSite,
@NotNull PsiMethod method1,
@NotNull LanguageLevel languageLevel,
@NotNull final LanguageLevel languageLevel,
boolean varargsPosition,
@NotNull PsiSubstitutor methodSubstitutor1,
@NotNull PsiMethod method2,
PsiSubstitutor siteSubstitutor1) {
@NotNull PsiMethod method2,
final PsiSubstitutor siteSubstitutor1) {
if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && method1.getTypeParameters().length > 0 && myArgumentsList instanceof PsiExpressionList) {
final PsiElement parent = myArgumentsList.getParent();
if (parent instanceof PsiCallExpression) {
return InferenceSession.isMoreSpecific(method2, method1, siteSubstitutor1, ((PsiExpressionList)myArgumentsList).getExpressions(), myArgumentsList, varargsPosition);
}
}
final PsiUtil.ApplicabilityChecker applicabilityChecker = languageLevel.isAtLeast(LanguageLevel.JDK_1_8)
? new PsiUtil.ApplicabilityChecker() {
final PsiUtil.ApplicabilityChecker applicabilityChecker = new PsiUtil.ApplicabilityChecker() {
@Override
public boolean isApplicable(PsiType left, PsiType right,
boolean allowUncheckedConversion, int argId) {
return isTypeMoreSpecific(left, right, argId);
public boolean isApplicable(PsiType left, PsiType right, boolean allowUncheckedConversion, int argId) {
if (right instanceof PsiClassType) {
final PsiClass rightClass = ((PsiClassType)right).resolve();
if (rightClass instanceof PsiTypeParameter) {
right = new PsiImmediateClassType(rightClass, siteSubstitutor1);
}
}
return languageLevel.isAtLeast(LanguageLevel.JDK_1_8) ? isTypeMoreSpecific(left, right, argId) : TypeConversionUtil.isAssignable(left, right, allowUncheckedConversion);
}
}
: PsiUtil.ApplicabilityChecker.ASSIGNABILITY_CHECKER;
};
final int applicabilityLevel = PsiUtil.getApplicabilityLevel(method1, methodSubstitutor1, types2AtSite, languageLevel, false, varargsPosition, applicabilityChecker);
return applicabilityLevel > MethodCandidateInfo.ApplicabilityLevel.NOT_APPLICABLE;
}
@@ -0,0 +1,5 @@
@interface Foo {
boolean foo();
}
@Foo(foo=<caret>)
@@ -0,0 +1,6 @@
@interface Foo {
MyEnum value();
}
enum MyEnum { x, y }
@Foo(<caret>)
@@ -0,0 +1,5 @@
@interface Foo {
int value();
}
@Foo(<caret>)
@@ -0,0 +1,5 @@
@interface Foo {
Class attr();
}
@Foo(attr = <caret>)
@@ -0,0 +1,5 @@
@interface Foo {
Class value();
}
@Foo(<caret>)
@@ -0,0 +1,21 @@
import java.util.ArrayList;
import java.util.List;
class Test {
public static class Foo<T> {
public void set(Iterable<T> v) {
System.out.println(v);
}
public <Y extends List<T>> void set(Y v) {
System.out.println(v);
}
}
static void main(Foo<Double> doubleFoo, ArrayList<Double> data) {
doubleFoo.set(data);
}
}
@@ -112,7 +112,13 @@ public class KeywordCompletionTest extends LightCompletionTestCase {
selectItem(myItems[0], '!');
checkResultByFile(BASE_PATH + "/" + getTestName(true) + "_after.java");
}
public void testNoPrimitivesInBooleanAnnotationAttribute() { doTest(1, "true", "int", "boolean"); }
public void testNoPrimitivesInIntAnnotationValueAttribute() { doTest(0, "true", "int", "boolean"); }
public void testNoPrimitivesInEnumAnnotationAttribute() { doTest(0, "true", "int", "boolean"); }
public void testPrimitivesInClassAnnotationValueAttribute() { doTest(2, "true", "int", "boolean"); }
public void testPrimitivesInClassAnnotationAttribute() { doTest(3, "true", "int", "boolean"); }
public void testImportStatic() throws Exception { doTest(1, "static"); }
public void testAbstractInInterface() throws Exception { doTest(1, "abstract"); }
public void testCharInAnnotatedParameter() throws Exception { doTest(1, "char"); }
@@ -54,7 +54,7 @@ class Foo {
myFixture.configureByText "a.java", """
class Bar {
static void foo(ModifierList ml) {
static void foo() {
if (getConstant() == <caret>) {}
}
@@ -75,6 +75,28 @@ interface Foo {
myFixture.assertPreferredCompletionItems 0, 'BAR', 'FOO'
}
public void "test magic constant in equality before another equality"() {
addMagicConstant()
myFixture.configureByText "a.java", """
class Bar {
static void foo() {
if (getConstant() == <caret>getConstant() == 2) {}
}
@org.intellij.lang.annotations.MagicConstant(flagsFromClass = Foo.class)
public native int getConstant();
}
interface Foo {
int FOO = 1;
int BAR = 2;
}
"""
myFixture.complete(CompletionType.SMART)
myFixture.assertPreferredCompletionItems 0, 'BAR', 'FOO'
}
private PsiClass addModifierList() {
addMagicConstant()
@@ -159,6 +159,10 @@ public class OverloadResolutionTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testSiteSubstituteTypeParameterBoundsWhenCheckForMostSpecific() throws Exception {
doTest();
}
private void doTest() {
doTest(true);
}
@@ -227,9 +227,11 @@ public class JavadocFormatterTest extends AbstractJavaFormatterTest {
getSettings().getRootSettings().ENABLE_JAVADOC_FORMATTING = true;
getSettings().getRootSettings().WRAP_COMMENTS = true;
getSettings().RIGHT_MARGIN = 20;
LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_7);
doTextTest("/**\n" + " * <p />\n" + " * Another paragraph of the description placed after blank line.\n" + " */\n" + "class A{}",
doTextTest("/**\n" +
" * <p />\n" +
" * Another paragraph of the description placed after blank line.\n" +
" */\n" +
"class A{}",
"/**\n" +
" * <p/>\n" +
" * Another paragraph\n" +
@@ -240,26 +242,36 @@ public class JavadocFormatterTest extends AbstractJavaFormatterTest {
"class A {\n" +
"}");
}
public void testSCR2632_JDK8_LanguageLevel() throws Exception {
public void test_PreserveExistingSelfClosingTags_AndGenerateOnlyPTag() {
getSettings().getRootSettings().ENABLE_JAVADOC_FORMATTING = true;
getSettings().getRootSettings().WRAP_COMMENTS = true;
getSettings().RIGHT_MARGIN = 20;
LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_8);
doTextTest("/**\n" + " * <p />\n" + " * Another paragraph of the description placed after blank line.\n" + " */\n" + "class A{}",
"/**\n" +
" * <p>\n" +
" * Another paragraph\n" +
" * of the description\n" +
" * placed after\n" +
" * blank line.\n" +
" */\n" +
"class A {\n" +
"}");
LanguageLevel before = LanguageLevelProjectExtension.getInstance(getProject()).getLanguageLevel();
LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_7);
try {
doTextTest(
"/**\n" +
" * My test comment\n" +
" * <p/>\n" +
" * \n" +
" * With empty line\n" +
" */\n" +
"class T {\n" +
"}",
"/**\n" +
" * My test comment\n" +
" * <p/>\n" +
" * <p>\n" +
" * With empty line\n" +
" */\n" +
"class T {\n" +
"}"
);
}
finally {
LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(before);
}
}
public void testParagraphTagGeneration() {
// Inspired by IDEA-61811
getSettings().getRootSettings().ENABLE_JAVADOC_FORMATTING = true;
@@ -280,7 +292,7 @@ public class JavadocFormatterTest extends AbstractJavaFormatterTest {
"}",
"/**\n" +
" * line 1\n" +
" * <p/>\n" +
" * <p>\n" +
" * line 2\n" +
" * <pre>\n" +
" * line 3\n" +
@@ -793,7 +805,7 @@ public class JavadocFormatterTest extends AbstractJavaFormatterTest {
doClassTest(before, after);
}
public void testGenerateSelfClosingPTagIfLanguageLevelNotJava8() throws Exception {
public void testPTagIfLanguageLevelNotJava8() throws Exception {
getSettings().getRootSettings().JD_P_AT_EMPTY_LINES = true;
getSettings().getRootSettings().ENABLE_JAVADOC_FORMATTING = true;
LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_7);
@@ -806,7 +818,7 @@ public class JavadocFormatterTest extends AbstractJavaFormatterTest {
"}\n";
String after = "/**\n" +
" * Super method\n" +
" * <p/>\n" +
" * <p>\n" +
" * Super multiple times\n" +
" */\n" +
"public void voo() {\n" +
@@ -21,7 +21,6 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.structuralsearch.MatchOptions;
@@ -444,7 +443,6 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
final MatchingHandler allRemainingClassContentElementHandler = unmatchedHandlerName != null ? pattern.getHandler(unmatchedHandlerName) : null;
MatchContext.MatchedElementsListener newListener = null;
assert javaPattern instanceof JavaCompiledPattern;
if (allRemainingClassContentElementHandler != null) {
myMatchingVisitor.getMatchContext().setMatchedElementsListener(
newListener = new MatchContext.MatchedElementsListener() {
@@ -686,29 +684,47 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
myMatchingVisitor.setResult(false);
}
private static int countCStyleArrayDeclarationDims(final PsiElement type2) {
if (type2 != null) {
final PsiElement parentElement = type2.getParent();
if (parentElement instanceof PsiVariable) {
final PsiIdentifier psiIdentifier = ((PsiVariable)parentElement).getNameIdentifier();
if (psiIdentifier == null) return 0;
int count = 0;
for (PsiElement sibling = psiIdentifier.getNextSibling(); sibling != null; sibling = sibling.getNextSibling()) {
if (sibling instanceof PsiJavaToken) {
final IElementType tokenType = ((PsiJavaToken)sibling).getTokenType();
if (tokenType == JavaTokenType.LBRACKET) ++count;
else if (tokenType != JavaTokenType.RBRACKET) break;
}
}
return count;
}
private static int getArrayDimensions(final PsiElement element) {
if (element == null) {
return 0;
}
final PsiElement parent = element.getParent();
if (parent instanceof PsiVariable) {
final PsiVariable variable = (PsiVariable)parent;
final PsiType type = variable.getType();
return type.getArrayDimensions();
}
else if (parent instanceof PsiMethod) {
final PsiMethod method = (PsiMethod)parent;
final PsiType type = method.getReturnType();
return (type == null) ? 0 : type.getArrayDimensions();
}
else if (element instanceof PsiTypeElement) {
final PsiTypeElement typeElement = (PsiTypeElement)element;
final PsiType type = typeElement.getType();
return type.getArrayDimensions();
}
return 0;
}
private static PsiTypeElement getInnermostComponentTypeElement(PsiTypeElement typeElement) {
PsiElement child = typeElement.getFirstChild();
while (child instanceof PsiTypeElement) {
typeElement = (PsiTypeElement)child;
child = typeElement.getFirstChild();
}
return typeElement;
}
private static PsiElement getInnermostComponent(PsiElement element) {
if (!(element instanceof PsiTypeElement)) {
return element;
}
final PsiTypeElement typeElement = (PsiTypeElement)element;
final PsiJavaCodeReferenceElement referenceElement = typeElement.getInnermostComponentReferenceElement();
return (referenceElement != null) ? referenceElement : getInnermostComponentTypeElement(typeElement);
}
private void copyResults(final MatchResultImpl ourResult) {
if (ourResult.hasSons()) {
for (MatchResult son : ourResult.getAllSons()) {
@@ -717,93 +733,62 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
}
}
private boolean matchType(final PsiElement _type, final PsiElement _type2) {
PsiElement el = _type;
PsiElement el2 = _type2;
PsiType type1 = null;
PsiType type2 = null;
private boolean matchType(final PsiElement patternType, final PsiElement matchedType) {
PsiElement patternElement = getInnermostComponent(patternType);
PsiElement matchedElement = getInnermostComponent(matchedType);
// check for generics
if (_type instanceof PsiTypeElement &&
((PsiTypeElement)_type).getInnermostComponentReferenceElement() != null
) {
el = ((PsiTypeElement)_type).getInnermostComponentReferenceElement();
type1 = ((PsiTypeElement)_type).getType();
}
if (_type2 instanceof PsiTypeElement &&
((PsiTypeElement)_type2).getInnermostComponentReferenceElement() != null
) {
el2 = ((PsiTypeElement)_type2).getInnermostComponentReferenceElement();
type2 = ((PsiTypeElement)_type2).getType();
}
PsiElement[] typeparams = null;
if (el2 instanceof PsiJavaCodeReferenceElement) {
final PsiReferenceParameterList parameterList = ((PsiJavaCodeReferenceElement)el2).getParameterList();
PsiElement[] typeParameters = null;
if (matchedElement instanceof PsiJavaCodeReferenceElement) {
final PsiReferenceParameterList parameterList = ((PsiJavaCodeReferenceElement)matchedElement).getParameterList();
if (parameterList != null) {
typeparams = parameterList.getTypeParameterElements();
typeParameters = parameterList.getTypeParameterElements();
}
}
else if (el2 instanceof PsiTypeParameter) {
el2 = ((PsiTypeParameter)el2).getNameIdentifier();
else if (matchedElement instanceof PsiTypeParameter) {
matchedElement = ((PsiTypeParameter)matchedElement).getNameIdentifier();
}
else if (el2 instanceof PsiClass && ((PsiClass)el2).hasTypeParameters()) {
typeparams = ((PsiClass)el2).getTypeParameters();
el2 = ((PsiClass)el2).getNameIdentifier();
else if (matchedElement instanceof PsiClass && ((PsiClass)matchedElement).hasTypeParameters()) {
typeParameters = ((PsiClass)matchedElement).getTypeParameters();
matchedElement = ((PsiClass)matchedElement).getNameIdentifier();
}
else if (el2 instanceof PsiMethod && ((PsiMethod)el2).hasTypeParameters()) {
typeparams = ((PsiMethod)_type2).getTypeParameters();
el2 = ((PsiMethod)_type2).getNameIdentifier();
else if (matchedElement instanceof PsiMethod && ((PsiMethod)matchedElement).hasTypeParameters()) {
typeParameters = ((PsiMethod)matchedType).getTypeParameters();
matchedElement = ((PsiMethod)matchedType).getNameIdentifier();
}
PsiReferenceParameterList list = null;
if (el instanceof PsiJavaCodeReferenceElement) {
list = ((PsiJavaCodeReferenceElement)el).getParameterList();
el = ((PsiJavaCodeReferenceElement)el).getReferenceNameElement();
}
if (list != null && list.getTypeParameterElements().length > 0) {
boolean result = typeparams != null && myMatchingVisitor.matchSequentially(list.getTypeParameterElements(), typeparams);
if (!result) return false;
}
else {
if (_type2 instanceof PsiTypeElement) {
type2 = ((PsiTypeElement)_type2).getType();
if (typeparams == null || typeparams.length == 0) {
final PsiJavaCodeReferenceElement innermostComponentReferenceElement =
((PsiTypeElement)_type2).getInnermostComponentReferenceElement();
if (innermostComponentReferenceElement != null) el2 = innermostComponentReferenceElement;
}
else {
el2 = _type2;
}
}
}
final int array2Dims = (type2 != null ? type2.getArrayDimensions() : 0) + countCStyleArrayDeclarationDims(_type2);
final int arrayDims = (type1 != null ? type1.getArrayDimensions() : 0) + countCStyleArrayDeclarationDims(_type);
if (myMatchingVisitor.getMatchContext().getPattern().isTypedVar(el)) {
final SubstitutionHandler handler = (SubstitutionHandler)myMatchingVisitor.getMatchContext().getPattern().getHandler(el);
RegExpPredicate regExpPredicate = null;
if (arrayDims != 0) {
if (arrayDims != array2Dims) {
if (patternElement instanceof PsiJavaCodeReferenceElement) {
final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)patternElement;
final PsiReferenceParameterList list = referenceElement.getParameterList();
if (list != null) {
final PsiTypeElement[] elements = list.getTypeParameterElements();
if (elements.length > 0 && (typeParameters == null || !myMatchingVisitor.matchSequentially(elements, typeParameters))) {
return false;
}
}
else if (array2Dims != 0) {
patternElement = referenceElement.getReferenceNameElement();
}
final int matchedArrayDimensions = getArrayDimensions(matchedType);
final int patternArrayDimensions = getArrayDimensions(patternType);
if (myMatchingVisitor.getMatchContext().getPattern().isTypedVar(patternElement)) {
final SubstitutionHandler handler = (SubstitutionHandler)myMatchingVisitor.getMatchContext().getPattern().getHandler(patternElement);
RegExpPredicate regExpPredicate = null;
if (patternArrayDimensions != 0) {
if (patternArrayDimensions != matchedArrayDimensions) {
return false;
}
}
else if (matchedArrayDimensions != 0) {
regExpPredicate = MatchingHandler.getSimpleRegExpPredicate(handler);
if (regExpPredicate != null) {
regExpPredicate.setNodeTextGenerator(new RegExpPredicate.NodeTextGenerator() {
public String getText(PsiElement element) {
StringBuilder builder = new StringBuilder(RegExpPredicate.getMeaningfulText(element));
for (int i = 0; i < array2Dims; ++i) builder.append("[]");
for (int i = 0; i < matchedArrayDimensions; ++i) builder.append("[]");
return builder.toString();
}
});
@@ -812,10 +797,10 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
try {
if (handler.isSubtype() || handler.isStrictSubtype()) {
return checkMatchWithingHierarchy(el2, handler, el);
return checkMatchWithingHierarchy(matchedElement, handler, patternElement);
}
else {
return handler.handle(el2, myMatchingVisitor.getMatchContext());
return handler.handle(matchedElement, myMatchingVisitor.getMatchContext());
}
}
finally {
@@ -823,31 +808,31 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
}
}
if (array2Dims != arrayDims) {
if (matchedArrayDimensions != patternArrayDimensions) {
return false;
}
if (el instanceof PsiIdentifier) {
final PsiElement parent = el.getParent();
if (patternElement instanceof PsiIdentifier) {
final PsiElement parent = patternElement.getParent();
if (parent instanceof PsiJavaCodeReferenceElement) {
el = parent;
patternElement = parent;
}
}
if (el2 instanceof PsiIdentifier) {
final PsiElement parent = el2.getParent();
if (matchedElement instanceof PsiIdentifier) {
final PsiElement parent = matchedElement.getParent();
if (parent instanceof PsiJavaCodeReferenceElement) {
el2 = parent;
matchedElement = parent;
}
}
final String text = getText(el);
final String text2 = getText(el2);
final String text = getText(patternElement);
final String text2 = getText(matchedElement);
final boolean caseSensitive = myMatchingVisitor.getMatchContext().getOptions().isCaseSensitiveMatch();
final boolean equalsIgnorePackage = MatchUtils.compareWithNoDifferenceToPackage(text, text2, !caseSensitive);
if (equalsIgnorePackage || !(el2 instanceof PsiJavaReference)) {
if (equalsIgnorePackage || !(matchedElement instanceof PsiJavaReference)) {
return equalsIgnorePackage;
}
else {
final PsiElement element2 = ((PsiJavaReference)el2).resolve();
final PsiElement element2 = ((PsiJavaReference)matchedElement).resolve();
if (element2 instanceof PsiClass) {
final String name = ((PsiClass)element2).getQualifiedName();
@@ -47,19 +47,19 @@ public class GuavaInspectionTest extends JavaCodeInsightFixtureTestCase {
moduleBuilder.addJdk(IdeaTestUtil.getMockJdk18Path().getPath());
}
public void _testOptional() {
public void testOptional() {
doTest();
}
public void _testOptional2() {
public void testOptional2() {
doTest();
}
public void _testSimpleFluentIterable() {
public void testSimpleFluentIterable() {
doTest();
}
public void _testChainedFluentIterable() {
public void testChainedFluentIterable() {
doTest();
}
@@ -67,7 +67,7 @@ public class GuavaInspectionTest extends JavaCodeInsightFixtureTestCase {
doTest();
}
public void _testChainedFluentIterableWithChainedInitializer() {
public void testChainedFluentIterableWithChainedInitializer() {
doTest();
}
+1 -1
View File
@@ -127,7 +127,7 @@ void PrintRemapForSubstDrives() {
const int BUFSIZE = 1024;
void PrintDirectoryReparsePoint(const char *path) {
int size = strlen(path) + 2;
int size = (int)(strlen(path) + 2);
char *directory = (char *) malloc(size);
strcpy_s(directory, size, path);
NormalizeSlashes(directory, '\\');
+6
View File
@@ -8,13 +8,19 @@ EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0EF2C2DB-0E16-4BC3-9927-9C51AF00EB57}.Debug|Win32.ActiveCfg = Debug|Win32
{0EF2C2DB-0E16-4BC3-9927-9C51AF00EB57}.Debug|Win32.Build.0 = Debug|Win32
{0EF2C2DB-0E16-4BC3-9927-9C51AF00EB57}.Debug|x64.ActiveCfg = Debug|x64
{0EF2C2DB-0E16-4BC3-9927-9C51AF00EB57}.Debug|x64.Build.0 = Debug|x64
{0EF2C2DB-0E16-4BC3-9927-9C51AF00EB57}.Release|Win32.ActiveCfg = Release|Win32
{0EF2C2DB-0E16-4BC3-9927-9C51AF00EB57}.Release|Win32.Build.0 = Release|Win32
{0EF2C2DB-0E16-4BC3-9927-9C51AF00EB57}.Release|x64.ActiveCfg = Release|x64
{0EF2C2DB-0E16-4BC3-9927-9C51AF00EB57}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+75
View File
@@ -5,10 +5,18 @@
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{0EF2C2DB-0E16-4BC3-9927-9C51AF00EB57}</ProjectGuid>
@@ -22,20 +30,37 @@
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v120_xp</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v120_xp</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v120_xp</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>12.0.21005.1</_ProjectFileVersion>
@@ -46,12 +71,24 @@
<LinkIncremental>false</LinkIncremental>
<TargetName>fsnotifier</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>false</LinkIncremental>
<TargetName>fsnotifier64</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>false</LinkIncremental>
<TargetName>fsnotifier</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>false</LinkIncremental>
<TargetName>fsnotifier64</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
@@ -70,6 +107,24 @@
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>mpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
@@ -90,6 +145,26 @@
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeader />
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>mpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="fileWatcher3.cpp" />
</ItemGroup>
@@ -15,29 +15,29 @@
*/
package com.intellij.openapi.components;
import com.intellij.util.xmlb.XmlSerializer;
import org.jetbrains.annotations.Nullable;
/**
* Every component which would like to persist its state across IDEA restarts
* should implement this interface.
*
* See <a href="http://confluence.jetbrains.net/display/IDEADEV/Persisting+State+of+Components">JetBrains WIKI</a>
* See <a href="http://www.jetbrains.org/intellij/sdk/docs/basics/persisting_state_of_components.html">IntelliJ Platform SDK DevGuide</a>
* for detailed description.
*
* Implementation must be thread-safe - a component should expect these methods to be called at any moment of its lifecycle.
*/
public interface PersistentStateComponent<T> {
/**
* @return a component state. All properties and public fields are serialized. Only values, which differ
* @return a component state. All properties, public and annotated fields are serialized. Only values, which differ
* from default (i.e. the value of newly instantiated class) are serialized. <code>null</code> value indicates
* that no state should be stored
* @see XmlSerializer
* that no state should be stored.
* @see com.intellij.util.xmlb.XmlSerializer
*/
@Nullable
T getState();
/**
* This method is called when new component state is loaded. A component should expect this method
* to be called at any moment of its lifecycle. The method can and will be called several times, if
* This method is called when new component state is loaded. The method can and will be called several times, if
* config files were externally changed while IDEA running.
* @param state loaded component state
* @see com.intellij.util.xmlb.XmlSerializerUtil#copyBean(Object, Object)
@@ -0,0 +1,51 @@
/*
* Copyright 2000-2015 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;
import org.jetbrains.annotations.NotNull;
/**
* Implementing this interface allows for better control over the references associated with a PSI element.
* Instead of {@link PsiElement#getReferences()}, clients can call {@link #getReferences(PsiReferenceService.Hints)} and the implementation
* may use the hints for performance optimizations, e.g. to avoid finding and creating references that won't intersect the given offset
* ({@link com.intellij.psi.PsiReferenceService.Hints#offsetInElement}) or that have no change of resolving to a particular target
* ({@link com.intellij.psi.PsiReferenceService.Hints#target}).
*
* @since 144.*
* @author peter
*/
public interface HintedReferenceHost extends PsiElement {
/**
* Same as {@link PsiElement#getReferences()}, but the implementation may take hints into account and return only references that match these hints.
* But it's not a hard requirement, so the clients should not rely that only matching references will be returned.
* @param hints the hints about the desired references
* @return the array of references, or an empty array if the element has no associated references.
*/
@NotNull
PsiReference[] getReferences(@NotNull PsiReferenceService.Hints hints);
/**
* Normally in {@link PsiElement#findReferenceAt(int)}, all tree hierarchy is traversed bottom-up and each element is asked for references.
* Quite often it's not needed, because references tend to be contained close to the tree leaves, and their ancestors won't return anything
* useful for given offsets anyway. This method makes it possible to stop such bottom-up traversals early and thus improve performance,
* if the implementation knows for sure that no tree ancestor of this element can contain references matching the specified hints.
* @param hints the hints about the desired references
* @return false if there's no use in asking this element's ancestors for references with specified hints, true otherwise.
*/
boolean shouldAskParentForReferences(@NotNull PsiReferenceService.Hints hints);
}
@@ -686,10 +686,14 @@ public class IdeaPluginDescriptorImpl implements IdeaPluginDescriptor {
} catch (IOException e) {
path = getPath().getAbsolutePath();
}
if (ApplicationManager.getApplication() != null && ApplicationManager.getApplication().isInternal()) {
Application app = ApplicationManager.getApplication();
if (app != null && app.isInternal()) {
if (path.startsWith(PathManager.getHomePath() + File.separator + "out" + File.separator + "classes")) {
return true;
}
if (app.isUnitTestMode() && !path.startsWith(PathManager.getPluginsPath() + File.separatorChar)) {
return true;
}
}
return path.startsWith(PathManager.getPreInstalledPluginsPath());
@@ -780,16 +780,21 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
myCachedTokenType = null;
}
private IElementType remapCurrentToken() {
if (myCachedTokenType != null) return myCachedTokenType;
if (myRemapper != null) {
remapCurrentToken(myRemapper.filter(myLexTypes[myCurrentLexeme], myLexStarts[myCurrentLexeme],
myLexStarts[myCurrentLexeme + 1], myLexer.getBufferSequence()));
}
return myLexTypes[myCurrentLexeme];
}
private IElementType calcTokenType() {
if (eof()) return null;
if (myRemapper != null) {
IElementType type = myLexTypes[myCurrentLexeme];
type = myRemapper.filter(type, myLexStarts[myCurrentLexeme], myLexStarts[myCurrentLexeme + 1], myLexer.getBufferSequence());
myLexTypes[myCurrentLexeme] = type; // filter may have changed the type
//remaps current token, and following, which remaps to spaces and comments
skipWhitespace();
type = myLexTypes[myCurrentLexeme];
return type;
}
return myLexTypes[myCurrentLexeme];
}
@@ -870,7 +875,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
}
private void skipWhitespace() {
while (myCurrentLexeme < myLexemeCount && whitespaceOrComment(myLexTypes[myCurrentLexeme])) {
while (myCurrentLexeme < myLexemeCount && whitespaceOrComment(remapCurrentToken())) {
onSkip(myLexTypes[myCurrentLexeme], myLexStarts[myCurrentLexeme], myCurrentLexeme + 1 < myLexemeCount ? myLexStarts[myCurrentLexeme + 1] : myText.length());
myCurrentLexeme++;
clearCachedTokenType();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
* Copyright 2000-2015 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.
@@ -33,6 +33,7 @@ public class EditorDocumentPriorities {
public static final int RANGE_MARKER = 40;
public static final int FOLD_MODEL = 60;
public static final int LOGICAL_POSITION_CACHE = 65;
public static final int EDITOR_TEXT_LAYOUT_CACHE = 70;
public static final int EDITOR_TEXT_WIDTH_CACHE = 75;
public static final int LEXER_EDITOR = 80;
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 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.
@@ -22,6 +22,7 @@
*/
package com.intellij.openapi.progress.util;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.StandardProgressIndicator;
import com.intellij.openapi.progress.WrappedProgressIndicator;
@@ -30,8 +31,11 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ProgressWrapper extends AbstractProgressIndicatorBase implements WrappedProgressIndicator, StandardProgressIndicator {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.progress.util.ProgressWrapper");
private final ProgressIndicator myOriginal;
private final boolean myCheckCanceledForMe;
private final int nested;
protected ProgressWrapper(@NotNull ProgressIndicator original) {
this(original, false);
@@ -40,9 +44,12 @@ public class ProgressWrapper extends AbstractProgressIndicatorBase implements Wr
protected ProgressWrapper(@NotNull ProgressIndicator original, boolean checkCanceledForMe) {
myOriginal = original;
myCheckCanceledForMe = checkCanceledForMe;
nested = 1 + (original instanceof ProgressWrapper ? ((ProgressWrapper)original).nested : -1);
if (nested > 50) {
LOG.error("Too many wrapped indicators");
}
}
@Override
public final void cancel() {
super.cancel();
@@ -31,8 +31,9 @@ public class PsiReferenceServiceImpl extends PsiReferenceService {
if (element instanceof ContributedReferenceHost) {
return Arrays.asList(ReferenceProvidersRegistry.getReferencesFromProviders(element, hints));
}
else {
return Arrays.asList(element.getReferences());
if (element instanceof HintedReferenceHost) {
return Arrays.asList(((HintedReferenceHost)element).getReferences(hints));
}
return Arrays.asList(element.getReferences());
}
}
@@ -47,8 +47,12 @@ public class SharedPsiElementImplUtil {
List<PsiReference> referencesList = new ArrayList<PsiReference>();
while (element != null) {
addReferences(offset, element, referencesList);
offset = element.getStartOffsetInParent() + offset;
if (element instanceof PsiFile) break;
if (element instanceof HintedReferenceHost &&
!((HintedReferenceHost)element).shouldAskParentForReferences(new PsiReferenceService.Hints(null, offset))) {
break;
}
offset = element.getStartOffsetInParent() + offset;
element = element.getParent();
}
@@ -64,9 +68,15 @@ public class SharedPsiElementImplUtil {
}
private static void addReferences(int offset, PsiElement element, final Collection<PsiReference> outReferences) {
for (final PsiReference reference : element.getReferences()) {
PsiReference[] references;
if (element instanceof HintedReferenceHost) {
references = ((HintedReferenceHost)element).getReferences(new PsiReferenceService.Hints(null, offset));
} else {
references = element.getReferences();
}
for (final PsiReference reference : references) {
if (reference == null) {
LOG.error(element);
LOG.error("Null reference returned from " + element + " of " + element.getClass());
continue;
}
for (TextRange range : ReferenceRange.getRanges(reference)) {
@@ -15,6 +15,7 @@
*/
package com.intellij.ide.ui;
import com.intellij.util.ui.UIUtil;
import sun.swing.SwingUtilities2;
import java.awt.*;
@@ -24,29 +25,31 @@ public enum AntialiasingType {
GREYSCALE,
OFF;
private static final SwingUtilities2.AATextInfo aaEnabled =
new SwingUtilities2.AATextInfo(RenderingHints.VALUE_TEXT_ANTIALIAS_ON, 140);
private static final SwingUtilities2.AATextInfo lcdEnabled =
new SwingUtilities2.AATextInfo(RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB, 140);
private static final SwingUtilities2.AATextInfo aaDisabled = null;
private static SwingUtilities2.AATextInfo getLCDEnabledTextInfo () {
return new SwingUtilities2.AATextInfo(RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB, UIUtil.getLcdContrastValue());
}
private static SwingUtilities2.AATextInfo getAAEnabledTextInfo () {
return new SwingUtilities2.AATextInfo(RenderingHints.VALUE_TEXT_ANTIALIAS_ON, UIUtil.getLcdContrastValue());
}
public static Object getAAHintForSwingComponent() {
UISettings uiSettings = UISettings.getInstance();
if (uiSettings == null) return aaEnabled;
if (uiSettings == null) return getAAEnabledTextInfo();
switch (uiSettings.IDE_AA_TYPE) {
case SUBPIXEL:
return lcdEnabled;
return getLCDEnabledTextInfo();
case GREYSCALE:
return aaEnabled;
return getAAEnabledTextInfo();
case OFF:
return aaDisabled;
}
return aaEnabled;
return getAAEnabledTextInfo();
}
public Object getRenderingHintValue () {
@@ -281,6 +281,9 @@ public class UISettings extends SimpleModificationTracker implements PersistentS
*/
public static void setupAntialiasing(final Graphics g) {
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(RenderingHints.KEY_TEXT_LCD_CONTRAST, UIUtil.getLcdContrastValue());
Application application = ApplicationManager.getApplication();
if (application == null) {
// We cannot use services while Aplication has not been loaded yet
@@ -289,7 +292,6 @@ public class UISettings extends SimpleModificationTracker implements PersistentS
return;
}
Graphics2D g2d = (Graphics2D)g;
UISettings uiSettings = getInstance();
if (uiSettings != null) {
@@ -0,0 +1,119 @@
/*
* Copyright 2000-2015 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.application.options.codeStyle;
import com.intellij.openapi.application.ApplicationBundle;
import com.intellij.openapi.fileChooser.FileChooserFactory;
import com.intellij.openapi.fileChooser.FileSaverDescriptor;
import com.intellij.openapi.fileChooser.FileSaverDialog;
import com.intellij.openapi.options.SchemeExporter;
import com.intellij.openapi.options.SchemeExporterEP;
import com.intellij.openapi.options.SchemeExporterException;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.ui.popup.PopupStep;
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileWrapper;
import com.intellij.psi.codeStyle.CodeStyleScheme;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @author Rustam Vishnyakov
*/
class CodeStyleSchemeExporterUI {
@NotNull private final Component myParentComponent;
@NotNull private final CodeStyleScheme myScheme;
@NotNull private final StatusCallback myStatusCallback;
CodeStyleSchemeExporterUI(@NotNull Component parentComponent, @NotNull CodeStyleScheme scheme, @NotNull StatusCallback statusCallback) {
myParentComponent = parentComponent;
myScheme = scheme;
myStatusCallback = statusCallback;
}
void export() {
ListPopup popup = JBPopupFactory.getInstance().createListPopup(
new BaseListPopupStep<String>(ApplicationBundle.message("code.style.scheme.exporter.ui.export.as.title"), enumExporters()) {
@Override
public PopupStep onChosen(final String selectedValue, boolean finalChoice) {
return doFinalStep(new Runnable() {
@Override
public void run() {
exportSchemeUsing(selectedValue);
}
});
}
});
popup.showInCenterOf(myParentComponent);
}
private static String[] enumExporters() {
List<String> names = new ArrayList<String>();
Collection<SchemeExporterEP<CodeStyleScheme>> extensions = SchemeExporterEP.getExtensions(CodeStyleScheme.class);
for (SchemeExporterEP<CodeStyleScheme> extension : extensions) {
names.add(extension.name);
}
return ArrayUtil.toStringArray(names);
}
private void exportSchemeUsing(@NotNull String exporterName) {
SchemeExporter<CodeStyleScheme> exporter = SchemeExporterEP.getExporter(exporterName, CodeStyleScheme.class);
if (exporter != null) {
String ext = exporter.getExtension();
FileSaverDialog saver =
FileChooserFactory.getInstance()
.createSaveFileDialog(new FileSaverDescriptor(
ApplicationBundle.message("code.style.scheme.exporter.ui.file.chooser.title"),
ApplicationBundle.message("code.style.scheme.exporter.ui.file.chooser.message"),
ext), myParentComponent);
VirtualFileWrapper target = saver.save(null, getFileNameSuggestion() + "." + ext);
if (target != null) {
VirtualFile targetFile = target.getVirtualFile(true);
if (targetFile != null) {
try {
exporter.exportScheme(myScheme, targetFile);
myStatusCallback
.showMessage(ApplicationBundle.message("code.style.scheme.exporter.ui.code.style.exported.message", myScheme.getName(),
targetFile.getPresentableUrl()), MessageType.INFO);
}
catch (SchemeExporterException e) {
myStatusCallback.showMessage(e.getMessage(), MessageType.ERROR);
}
}
else {
myStatusCallback.showMessage(ApplicationBundle.message("code.style.scheme.exporter.ui.cannot.write.message"), MessageType.ERROR);
}
}
}
}
private String getFileNameSuggestion() {
return myScheme.getName();
}
interface StatusCallback {
void showMessage(@NotNull String message, @NotNull MessageType messageType);
}
}
@@ -75,7 +75,7 @@
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Export..."/>
<text value="E&amp;xport..."/>
</properties>
</component>
<component id="816ef" class="javax.swing.JButton" binding="myImportButton" default-binding="true">
@@ -22,10 +22,7 @@ import com.intellij.openapi.application.ApplicationBundle;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDialog;
import com.intellij.openapi.fileChooser.FileChooserFactory;
import com.intellij.openapi.options.SchemeFactory;
import com.intellij.openapi.options.SchemeImportException;
import com.intellij.openapi.options.SchemeImporter;
import com.intellij.openapi.options.SchemeImporterEP;
import com.intellij.openapi.options.*;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.MessageType;
@@ -128,6 +125,19 @@ public class ManageCodeStyleSchemesDialog extends DialogWrapper {
});
}
if (SchemeExporterEP.getExtensions(CodeStyleScheme.class).isEmpty()) {
myExportButton.setVisible(false);
}
else {
myExportButton.setVisible(true);
myExportButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
exportSelectedScheme();
}
});
}
init();
}
@@ -453,4 +463,12 @@ public class ManageCodeStyleSchemesDialog extends DialogWrapper {
}
}
private void exportSelectedScheme() {
new CodeStyleSchemeExporterUI(myExportButton, getSelectedScheme(), new CodeStyleSchemeExporterUI.StatusCallback() {
@Override
public void showMessage(@NotNull String message, @NotNull MessageType messageType) {
showStatus(myExportButton, message, messageType);
}
}).export();
}
}
@@ -808,9 +808,24 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzerEx implements Pers
return;
}
if (HeavyProcessLatch.INSTANCE.isRunning()) {
if (myAlarm.isEmpty()) {
// wait for heavy processing to stop, re-schedule daemon but not too soon
myAlarm.addRequest(myUpdateRunnable, Math.max(mySettings.AUTOREPARSE_DELAY,100));
final Disposable removeListenerDisposable = Disposer.newDisposable();
Disposer.register(DaemonCodeAnalyzerImpl.this, removeListenerDisposable);
// wait for heavy processing to stop, re-schedule daemon but not too soon
HeavyProcessLatch.HeavyProcessListener heavyProcessListener = new HeavyProcessLatch.HeavyProcessListener() {
@Override
public void processStarted() {
}
@Override
public void processFinished() {
Disposer.dispose(removeListenerDisposable);
myAlarm.addRequest(myUpdateRunnable, Math.max(mySettings.AUTOREPARSE_DELAY, 100), ModalityState.NON_MODAL);
}
};
HeavyProcessLatch.INSTANCE.addListener(removeListenerDisposable, heavyProcessListener);
if (!HeavyProcessLatch.INSTANCE.isRunning()) {
// in case heavy operation finished right before listener added
heavyProcessListener.processFinished();
}
return;
}
@@ -468,7 +468,7 @@ public class LookupCellRenderer implements ListCellRenderer {
@Override
protected void applyAdditionalHints(@NotNull Graphics2D g) {
GraphicsUtil.setupAntialiasing(g);
super.applyAdditionalHints(g);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 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.
@@ -258,11 +258,13 @@ class EditVariableDialog extends DialogWrapper {
public void setValueAt(Object aValue, int row, int col) {
Variable variable = myVariables.get(row);
if (col == 0) {
String varName = (String) aValue;
Variable newVar = new Variable (varName, variable.getExpressionString(), variable.getDefaultValueString(),
variable.isAlwaysStopAt());
myVariables.set(row, newVar);
updateTemplateTextByVarNameChange(variable, newVar);
String varName = (String) aValue;
if (TemplateImplUtil.parseVariables("$" + varName + "$").containsKey(varName)) {
Variable newVar = new Variable(varName, variable.getExpressionString(), variable.getDefaultValueString(),
variable.isAlwaysStopAt());
myVariables.set(row, newVar);
updateTemplateTextByVarNameChange(variable, newVar);
}
}
else if (col == 1) {
variable.setExpressionString((String)aValue);
@@ -166,7 +166,7 @@ public class TemplateState implements Disposable {
}
private boolean isCaretOutsideCurrentSegment() {
if (myEditor != null) {
if (myEditor != null && myCurrentSegmentNumber >= 0) {
final int offset = myEditor.getCaretModel().getOffset();
return offset < mySegments.getSegmentStart(myCurrentSegmentNumber) || offset > mySegments.getSegmentEnd(myCurrentSegmentNumber);
}
@@ -0,0 +1,82 @@
/*
* Copyright 2000-2015 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.codeStyle;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.options.SchemeExporter;
import com.intellij.openapi.options.SchemeExporterException;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.codeStyle.CodeStyleScheme;
import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
/**
* Exports (copies) a code style scheme to an external file as is.
*
* @author Rustam Vishnyakov
*/
public class CodeStyleSchemeCopyExporter implements SchemeExporter<CodeStyleScheme> {
@Override
public void exportScheme(@NotNull final CodeStyleScheme scheme, @NotNull final VirtualFile targetFile) throws SchemeExporterException {
assert scheme instanceof CodeStyleSchemeImpl;
try {
final Element root = schemeToDom((CodeStyleSchemeImpl)scheme);
ApplicationManager.getApplication().runWriteAction(new ThrowableComputable<Boolean, IOException>() {
@Override
public Boolean compute() throws IOException {
writeToFile(targetFile, root);
return Boolean.TRUE;
}
});
}
catch (Exception e) {
throw new SchemeExporterException("Export failed: " + e.getMessage());
}
}
@Override
public String getExtension() {
return "xml";
}
private static Element schemeToDom(@NotNull CodeStyleSchemeImpl scheme) throws WriteExternalException {
Element newElement = new Element("code_scheme");
newElement.setAttribute("name", scheme.getName());
scheme.writeExternal(newElement);
return newElement;
}
private void writeToFile(@NotNull VirtualFile file, @NotNull Element element) throws IOException {
OutputStream targetStream = file.getOutputStream(this);
try {
OutputStreamWriter writer = new OutputStreamWriter(targetStream);
Format format = Format.getPrettyFormat();
format.setLineSeparator("\n");
new XMLOutputter(format).output(element, writer);
}
finally {
targetStream.close();
}
}
}
@@ -0,0 +1,41 @@
/*
* Copyright 2000-2015 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.openapi.options;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
/**
* Base interface to export a scheme.
*
* @author Rustam Vishnyakov
*/
public interface SchemeExporter <T extends Scheme> {
/**
* Writes a scheme to existing <code>targetFile</code>. An implementor may use <code>targetFile.getOutputStream()</code> method to
* obtain a stream to write to.
*
* @param scheme The scheme to export.
* @param targetFile The target virtual file.
* @throws SchemeExporterException
*/
void exportScheme(@NotNull T scheme, @NotNull VirtualFile targetFile) throws SchemeExporterException;
/**
* @return Target file extension without a dot, for example "xml".
*/
String getExtension();
}
@@ -0,0 +1,25 @@
/*
* Copyright 2000-2015 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.openapi.options;
/**
* @author Rustam Vishnyakov
*/
public class SchemeExporterException extends Exception {
public SchemeExporterException(String message) {
super(message);
}
}
@@ -15,9 +15,11 @@
*/
package com.intellij.ui;
import com.intellij.ide.ui.AntialiasingType;
import com.intellij.util.ObjectUtils;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import sun.swing.SwingUtilities2;
import javax.swing.*;
import java.awt.*;
@@ -33,6 +35,7 @@ public class ExpandedItemListCellRendererWrapper implements ListCellRenderer {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
list.putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY, AntialiasingType.getAAHintForSwingComponent());
Component result = myWrappee.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (!myHandler.getExpandedItems().contains(index)) return result;
Rectangle bounds = result.getBounds();
@@ -733,7 +733,6 @@ public class SimpleColoredComponent extends JComponent implements Accessible, Co
final List<Object[]> searchMatches = new ArrayList<Object[]>();
UISettings.setupAntialiasing(g);
applyAdditionalHints(g);
final Font ownFont = getFont();
if (ownFont != null) {
@@ -915,6 +914,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible, Co
}
protected void applyAdditionalHints(@NotNull Graphics2D g) {
UISettings.setupAntialiasing(g);
}
@Override
@@ -15,6 +15,7 @@
*/
package com.intellij.ui.components.editors;
import com.intellij.ide.ui.AntialiasingType;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupAdapter;
import com.intellij.openapi.ui.popup.JBPopupFactory;
@@ -31,6 +32,7 @@ import com.intellij.util.Function;
import com.intellij.util.PlatformIcons;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.EmptyIcon;
import sun.swing.SwingUtilities2;
import javax.swing.*;
import javax.swing.event.TableModelEvent;
@@ -78,6 +80,7 @@ public class JBComboBoxTableCellEditorComponent extends JBLabel {
} else {
label.setIcon(getEmptyIcon());
}
label.putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY, AntialiasingType.getAAHintForSwingComponent());
return label;
}
@@ -149,11 +149,6 @@ public class TabLabel extends JPanel {
g.setClip(oldClip);
}
}
@Override
protected void applyAdditionalHints(@NotNull Graphics2D g) {
UISettings.setupAntialiasing(g);
}
};
label.setOpaque(false);
label.setBorder(null);
@@ -175,6 +175,11 @@ public class AppearanceConfigurable extends BaseConfigurable implements Searchab
if (!myComponent.myAntialiasingInIDE.getSelectedItem().equals(settings.IDE_AA_TYPE)) {
settings.IDE_AA_TYPE = (AntialiasingType)myComponent.myAntialiasingInIDE.getSelectedItem();
for (Window w : Window.getWindows()) {
for (JComponent c : UIUtil.uiTraverser(w).filter(JComponent.class)) {
c.putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY, AntialiasingType.getAAHintForSwingComponent());
}
}
shouldUpdateUI = true;
}
@@ -523,8 +528,10 @@ public class AppearanceConfigurable extends BaseConfigurable implements Searchab
}
private static class AAListCellRenderer extends ListCellRendererWrapper<AntialiasingType> {
private static final SwingUtilities2.AATextInfo SUBPIXEL_HINT = new SwingUtilities2.AATextInfo(RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB, 140);
private static final SwingUtilities2.AATextInfo GREYSCALE_HINT = new SwingUtilities2.AATextInfo(RenderingHints.VALUE_TEXT_ANTIALIAS_ON, 140);
private static final SwingUtilities2.AATextInfo SUBPIXEL_HINT = new SwingUtilities2.AATextInfo(
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB, UIUtil.getLcdContrastValue());
private static final SwingUtilities2.AATextInfo GREYSCALE_HINT = new SwingUtilities2.AATextInfo(
RenderingHints.VALUE_TEXT_ANTIALIAS_ON, UIUtil.getLcdContrastValue());
@Override
public void customize(JList list, AntialiasingType value, int index, boolean selected, boolean hasFocus) {
@@ -91,7 +91,7 @@ public class DebugAttachDetector {
}
myAlarm.request();
}
}, 5000, Alarm.ThreadToUse.POOLED_THREAD, null);
}, 5000, Alarm.ThreadToUse.POOLED_THREAD, app);
myAlarm.request();
}
}
@@ -328,7 +328,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
assertIsDispatchThread();
myProject = project;
myDocument = (DocumentEx)document;
if (myDocument instanceof DocumentImpl) {
if (myDocument instanceof DocumentImpl && !myUseNewRendering) {
((DocumentImpl)myDocument).requestTabTracking();
}
myScheme = createBoundColorSchemeDelegate(null);
@@ -888,7 +888,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
if (myConnection != null) {
myConnection.disconnect();
}
if (myDocument instanceof DocumentImpl) {
if (myDocument instanceof DocumentImpl && !myUseNewRendering) {
((DocumentImpl)myDocument).giveUpTabTracking();
}
Disposer.dispose(myDisposable);
@@ -1955,7 +1955,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
public boolean hasTabs() {
return !(myDocument instanceof DocumentImpl) || ((DocumentImpl)myDocument).mightContainTabs();
return myUseNewRendering || !(myDocument instanceof DocumentImpl) || ((DocumentImpl)myDocument).mightContainTabs();
}
public boolean isScrollToCaret() {
@@ -0,0 +1,88 @@
/*
* Copyright 2000-2015 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.openapi.editor.impl.view;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
/**
* Used for quick estimation of editor's viewable area size (without full text layout)
*/
class ApproximationFragment implements LineFragment {
private final int myLength;
private final int myColumnCount;
private final float myWidth;
ApproximationFragment(int length, int columnCount, float charWidth) {
myLength = length;
myColumnCount = columnCount;
myWidth = charWidth * columnCount;
}
@Override
public int getLength() {
return myLength;
}
@Override
public int getLogicalColumnCount(int startColumn) {
return myColumnCount;
}
@Override
public int getVisualColumnCount(float startX) {
return myColumnCount;
}
@Override
public int logicalToVisualColumn(float startX, int startColumn, int column) {
return column;
}
@Override
public int visualToLogicalColumn(float startX, int startColumn, int column) {
return column;
}
@Override
public float visualColumnToX(float startX, int column) {
return column < myColumnCount ? 0 : myWidth;
}
@Override
public int[] xToVisualColumn(float startX, float x) {
float relX = x - startX;
int column = relX < myWidth / 2 ? 0 : myColumnCount;
return new int[] {column, relX <= visualColumnToX(startX, column) ? 0 : 1};
}
@Override
public float offsetToX(float startX, int startOffset, int offset) {
return offset < myLength ? 0 : myWidth;
}
@Override
public void draw(Graphics2D g, float x, float y, int startColumn, int endColumn) {
throw new UnsupportedOperationException();
}
@NotNull
@Override
public LineFragment subFragment(int startOffset, int endOffset) {
throw new UnsupportedOperationException();
}
}
@@ -15,7 +15,6 @@
*/
package com.intellij.openapi.editor.impl.view;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.ex.util.EditorUtil;
import com.intellij.openapi.editor.impl.EditorImpl;
@@ -55,58 +54,11 @@ class EditorCoordinateMapper {
@NotNull
LogicalPosition offsetToLogicalPosition(int offset) {
int textLength = myDocument.getTextLength();
if (offset <= 0 || textLength == 0) {
return new LogicalPosition(0, 0);
}
offset = Math.min(offset, textLength);
int line = myDocument.getLineNumber(offset);
offset = Math.min(offset, myDocument.getLineEndOffset(line));
int column = 0;
if (ApplicationManager.getApplication().isDispatchThread()) {
LineLayout lineLayout = myView.getTextLayoutCache().getLineLayout(line);
column = lineLayout.offsetToLogicalColumn(offset - myDocument.getLineStartOffset(line));
}
else {
CharSequence text = myDocument.getImmutableCharSequence();
int tabSize = myView.getTabSize();
for (int i = myDocument.getLineStartOffset(line); i < offset; i++) {
if (text.charAt(i) == '\t') {
column = (column / tabSize + 1) * tabSize;
}
else {
column++;
}
}
}
return new LogicalPosition(line, column);
return myView.getLogicalPositionCache().offsetToLogicalPosition(offset);
}
int logicalPositionToOffset(@NotNull LogicalPosition pos) {
int line = pos.line;
if (line >= myDocument.getLineCount()) return myDocument.getTextLength();
int lineStartOffset = myDocument.getLineStartOffset(line);
if (ApplicationManager.getApplication().isDispatchThread()) {
LineLayout lineLayout = myView.getTextLayoutCache().getLineLayout(line);
return lineStartOffset + lineLayout.logicalColumnToOffset(pos.column);
}
else {
int lineEndOffset = myDocument.getLineEndOffset(line);
CharSequence text = myDocument.getImmutableCharSequence();
int tabSize = myView.getTabSize();
int column = 0;
for (int i = lineStartOffset; i < lineEndOffset; i++) {
if (text.charAt(i) == '\t') {
column = (column / tabSize + 1) * tabSize;
}
else {
column++;
}
if (pos.column < column) return i;
}
return lineEndOffset;
}
return myView.getLogicalPositionCache().logicalPositionToOffset(pos);
}
@NotNull
@@ -121,7 +73,7 @@ class EditorCoordinateMapper {
int visualLine = offsetToVisualLine(offset, beforeSoftWrap);
int maxVisualColumn = 0;
int maxLogicalColumn = 0;
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, offset, beforeSoftWrap)) {
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, offset, beforeSoftWrap, false)) {
if (!pos.leansForward && offset == fragment.getVisualLineStartOffset()) {
return new VisualPosition(visualLine, fragment.getStartVisualColumn());
}
@@ -173,7 +125,7 @@ class EditorCoordinateMapper {
int maxVisualColumn = 0;
int maxLogicalColumn = 0;
int maxOffset = offset;
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, offset, false)) {
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, offset, false, false)) {
int minColumn = fragment.getStartVisualColumn();
int maxColumn = fragment.getEndVisualColumn();
if (column < minColumn || column == minColumn && !pos.leansRight) {
@@ -234,7 +186,7 @@ class EditorCoordinateMapper {
return myDocument.getLineNumber(offset) - myFoldingModel.getFoldedLinesCountBefore(offset) + softWrapsBeforeOrAtOffset;
}
private int visualLineToOffset(int visualLine) {
int visualLineToOffset(int visualLine) {
int start = 0;
int end = myDocument.getTextLength();
int current = 0;
@@ -288,7 +240,7 @@ class EditorCoordinateMapper {
if (visualLine < myView.getEditor().getVisibleLineCount()) {
int visualLineStartOffset = visualLineToOffset(visualLine);
int maxOffset = 0;
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, visualLineStartOffset, false)) {
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, visualLineStartOffset, false, false)) {
if (p.x <= fragment.getStartX()) {
int markerWidth = myView.getEditor().getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.AFTER_SOFT_WRAP);
float indent = fragment.getStartX() - markerWidth;
@@ -334,7 +286,7 @@ class EditorCoordinateMapper {
if (visualLine < myView.getEditor().getVisibleLineCount()) {
int visualLineStartOffset = visualLineToOffset(visualLine);
int maxOffset = 0;
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, visualLineStartOffset, false)) {
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, visualLineStartOffset, false, false)) {
if (column < fragment.getStartVisualColumn()) {
break;
}
@@ -365,7 +317,7 @@ class EditorCoordinateMapper {
float x = getStartX(logicalLine);
if (myDocument.getTextLength() > 0) {
boolean firstFragment = true;
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, offset, beforeSoftWrap)) {
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, offset, beforeSoftWrap, false)) {
if (firstFragment && offset == visualLineStartOffset && !leanTowardsLargerOffsets) {
x = fragment.getStartX();
break;
@@ -465,7 +465,7 @@ class EditorPainter implements TextDrawingCallback {
Collection<LineExtensionInfo> extensions = painter.getLineExtensions(project, virtualFile, line);
if (extensions != null) {
for (LineExtensionInfo info : extensions) {
LineLayout layout = new LineLayout(myView, info.getText(), info.getFontType(), g.getFontRenderContext());
LineLayout layout = new LineLayout(myView, info.getText(), info.getFontType());
g.setColor(info.getColor());
x = paintLineLayoutWithEffect(g, layout, x, y, info.getEffectColor(), info.getEffectType());
int currentLineWidth = (int)x;
@@ -584,7 +584,7 @@ class EditorPainter implements TextDrawingCallback {
}
}
else {
int maxWidth = myView.getMaxWidthInLineRange(startPosition.line, endPosition.line) - 1;
int maxWidth = myView.getMaxWidthInLineRange(startPosition.line, endPosition.line, false) - 1;
TFloatArrayList leadingRanges = adjustedLogicalRangeToVisualRanges(startOffset,
myView.visualPositionToOffset(new VisualPosition(
startPosition.line, Integer.MAX_VALUE, true)));
@@ -691,7 +691,7 @@ class EditorPainter implements TextDrawingCallback {
private TFloatArrayList logicalRangeToVisualRanges(int startOffset, int endOffset) {
assert startOffset <= endOffset;
TFloatArrayList result = new TFloatArrayList();
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, startOffset, false)) {
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, startOffset, false, false)) {
int minOffset = fragment.getMinOffset();
int maxOffset = fragment.getMaxOffset();
if (startOffset == endOffset) {
@@ -770,8 +770,9 @@ class EditorPainter implements TextDrawingCallback {
g.fillRect(startX, y, width, lineHeight - 1);
if (myDocument.getTextLength() > 0 && caret != null) {
int targetVisualColumn = caret.getVisualPosition().column;
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView,
caret.getVisualLineStart(), false)) {
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView,
caret.getVisualLineStart(),
false, false)) {
int startVisualColumn = fragment.getStartVisualColumn();
int endVisualColumn = fragment.getEndVisualColumn();
if (startVisualColumn < targetVisualColumn && endVisualColumn > targetVisualColumn ||
@@ -809,7 +810,7 @@ class EditorPainter implements TextDrawingCallback {
int prevEndOffset = -1;
boolean firstFragment = true;
int maxColumn = 0;
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, offset, false)) {
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, offset, false, false)) {
int fragmentStartOffset = fragment.getStartOffset();
int start = fragmentStartOffset;
int end = fragment.getEndOffset();
@@ -29,36 +29,35 @@ import com.intellij.openapi.editor.impl.EditorImpl;
import com.intellij.openapi.editor.impl.softwrap.mapping.IncrementalCacheUpdateEvent;
import com.intellij.openapi.editor.impl.softwrap.mapping.SoftWrapAwareDocumentParsingListenerAdapter;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import gnu.trove.TIntArrayList;
import gnu.trove.TIntHashSet;
import gnu.trove.TIntProcedure;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Calculates width (in pixels) of editor contents.
*/
class EditorSizeManager implements PrioritizedDocumentListener, Disposable, FoldingListener {
private static final int UNKNOWN_WIDTH = Integer.MAX_VALUE;
private static final int UNKNOWN_WIDTH = -1;
private final EditorView myView;
private final EditorImpl myEditor;
private final DocumentEx myDocument;
private final TIntArrayList myLineWidths = new TIntArrayList(); // cached widths of visual lines (in pixels)
// negative value means an estimated (not precise) width
// UNKNOWN_WIDTH(Integer.MAX_VALUE) means no value
// UNKNOWN_WIDTH(-1) means no value
private int myWidthInPixels;
private int myMaxLineWithExtensionWidth;
private int myWidestLineWithExtension;
private boolean myApproximateWidthCalculated;
private final TIntHashSet myLinesWithCreatedLayout = new TIntHashSet();
private final List<TextRange> myDeferredRanges = new ArrayList<TextRange>();
private final SoftWrapAwareDocumentParsingListenerAdapter mySoftWrapChangeListener = new SoftWrapAwareDocumentParsingListenerAdapter() {
@Override
public void onRecalculationEnd(@NotNull IncrementalCacheUpdateEvent event) {
@@ -112,15 +111,11 @@ class EditorSizeManager implements PrioritizedDocumentListener, Disposable, Fold
}
foldingChangeStartOffset = Integer.MAX_VALUE;
foldingChangeEndOffset = Integer.MIN_VALUE;
myLinesWithCreatedLayout.forEach(new TIntProcedure() {
@Override
public boolean execute(int logicalLine) {
onLineLayoutCreated(logicalLine);
return true;
}
});
myLinesWithCreatedLayout.clear();
for (TextRange range : myDeferredRanges) {
onTextLayoutPerformed(range.getStartOffset(), range.getEndOffset());
}
myDeferredRanges.clear();
}
private void onSoftWrapRecalculationEnd(IncrementalCacheUpdateEvent event) {
@@ -128,7 +123,8 @@ class EditorSizeManager implements PrioritizedDocumentListener, Disposable, Fold
}
Dimension getPreferredSize() {
int width = getPreferredWidth();
int widthWithoutCaret = getPreferredWidth();
int width = widthWithoutCaret;
if (!myDocument.isInBulkUpdate()) {
for (Caret caret : myEditor.getCaretModel().getAllCarets()) {
if (caret.isUpToDate()) {
@@ -137,10 +133,18 @@ class EditorSizeManager implements PrioritizedDocumentListener, Disposable, Fold
}
}
}
width += myEditor.getSettings().getAdditionalColumnsCount() * myView.getPlainSpaceWidth();
if (shouldRespectAdditionalColumns(widthWithoutCaret)) {
width += myEditor.getSettings().getAdditionalColumnsCount() * myView.getPlainSpaceWidth();
}
return new Dimension(width, myEditor.getPreferredHeight());
}
private boolean shouldRespectAdditionalColumns(int widthWithoutCaret) {
return !myEditor.getSoftWrapModel().isSoftWrappingEnabled()
|| myEditor.getSoftWrapModel().isRespectAdditionalColumns()
|| widthWithoutCaret > myEditor.getScrollingModel().getVisibleArea().getWidth();
}
private int getPreferredWidth() {
if (myWidthInPixels < 0) {
myWidthInPixels = calculatePreferredWidth();
@@ -171,15 +175,7 @@ class EditorSizeManager implements PrioritizedDocumentListener, Disposable, Fold
for (int i = 0; i < lineCount; i++) {
int width = myLineWidths.get(i);
if (width == UNKNOWN_WIDTH) {
myApproximateWidthCalculated = false;
myView.getTextLayoutCache().enableQuickLayouts(true);
try {
width = myView.getMaxWidthInLineRange(i, i);
}
finally {
myView.getTextLayoutCache().enableQuickLayouts(false);
}
if (myApproximateWidthCalculated) width = - width;
width = myView.getMaxWidthInLineRange(i, i, true);
myLineWidths.set(i, width);
}
maxWidth = Math.max(maxWidth, Math.abs(width));
@@ -217,38 +213,28 @@ class EditorSizeManager implements PrioritizedDocumentListener, Disposable, Fold
myMaxLineWithExtensionWidth = width;
}
void quickLineLayoutCreated() {
myApproximateWidthCalculated = true;
}
void lineLayoutCreated(int logicalLine) {
void textLayoutPerformed(int startOffset, int endOffset) {
if (myEditor.getFoldingModel().isInBatchFoldingOperation()) {
myLinesWithCreatedLayout.add(logicalLine);
myDeferredRanges.add(new TextRange(startOffset, endOffset));
}
else {
onLineLayoutCreated(logicalLine);
onTextLayoutPerformed(startOffset, endOffset);
}
}
private void onLineLayoutCreated(int logicalLine) {
private void onTextLayoutPerformed(int startOffset, int endOffset) {
boolean purePaintingMode = myEditor.isPurePaintingMode();
boolean foldingEnabled = myEditor.getFoldingModel().isFoldingEnabled();
myEditor.setPurePaintingMode(false);
myEditor.getFoldingModel().setFoldingEnabled(true);
try {
int startVisualLine = myView.offsetToVisualLine(myDocument.getLineStartOffset(logicalLine), false);
int endVisualLine = myView.offsetToVisualLine(myDocument.getLineEndOffset(logicalLine), false);
boolean sizeInvalidated = false;
int startVisualLine = myView.offsetToVisualLine(startOffset, false);
int endVisualLine = myView.offsetToVisualLine(endOffset, true);
for (int i = startVisualLine; i <= endVisualLine; i++) {
if (myLineWidths.get(i) < 0) {
myLineWidths.set(i, UNKNOWN_WIDTH);
sizeInvalidated = true;
}
}
if (sizeInvalidated) {
myWidthInPixels = -1;
myEditor.getContentComponent().revalidate();
myLineWidths.set(i, UNKNOWN_WIDTH);
}
myWidthInPixels = -1;
myEditor.getContentComponent().revalidate();
}
finally {
myEditor.setPurePaintingMode(purePaintingMode);
@@ -55,6 +55,7 @@ public class EditorView implements TextDrawingCallback, Disposable {
private final EditorCoordinateMapper myMapper;
private final EditorSizeManager mySizeManager;
private final TextLayoutCache myTextLayoutCache;
private final LogicalPositionCache myLogicalPositionCache;
private final TabFragment myTabFragment;
private String myPrefixText; // accessed only in EDT
@@ -79,8 +80,10 @@ public class EditorView implements TextDrawingCallback, Disposable {
myMapper = new EditorCoordinateMapper(this);
mySizeManager = new EditorSizeManager(this);
myTextLayoutCache = new TextLayoutCache(this);
myLogicalPositionCache = new LogicalPositionCache(this);
myTabFragment = new TabFragment(this);
Disposer.register(this, myLogicalPositionCache);
Disposer.register(this, myTextLayoutCache);
Disposer.register(this, mySizeManager);
}
@@ -108,6 +111,10 @@ public class EditorView implements TextDrawingCallback, Disposable {
TabFragment getTabFragment() {
return myTabFragment;
}
LogicalPositionCache getLogicalPositionCache() {
return myLogicalPositionCache;
}
@Override
public void dispose() {
@@ -191,7 +198,7 @@ public class EditorView implements TextDrawingCallback, Disposable {
myPrefixText = prefixText;
synchronized (myLock) {
myPrefixLayout = prefixText == null || prefixText.isEmpty() ? null :
new LineLayout(this, prefixText, attributes.getFontType(), myFontRenderContext);
new LineLayout(this, prefixText, attributes.getFontType());
}
myPrefixAttributes = attributes;
mySizeManager.invalidateRange(0, 0);
@@ -231,18 +238,17 @@ public class EditorView implements TextDrawingCallback, Disposable {
public int getMaxWidthInRange(int startOffset, int endOffset) {
assertIsDispatchThread();
return getMaxWidthInLineRange(offsetToVisualLine(startOffset, false), offsetToVisualLine(endOffset, true));
return getMaxWidthInLineRange(offsetToVisualLine(startOffset, false), offsetToVisualLine(endOffset, true), false);
}
int getMaxWidthInLineRange(int startVisualLine, int endVisualLine) {
int getMaxWidthInLineRange(int startVisualLine, int endVisualLine, boolean quick) {
int maxWidth = 0;
endVisualLine = Math.min(endVisualLine, myEditor.getVisibleLineCount() - 1);
for (int i = startVisualLine; i <= endVisualLine; i++) {
LogicalPosition startPosition = visualToLogicalPosition(new VisualPosition(i, 0));
if (startPosition.line >= myDocument.getLineCount()) break;
int startOffset = logicalPositionToOffset(startPosition);
int startOffset = myMapper.visualLineToOffset(i);
float x = 0;
int maxOffset = 0;
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(this, startOffset, false)) {
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(this, startOffset, false, quick)) {
x = fragment.getEndX();
maxOffset = Math.max(maxOffset, fragment.getMaxOffset());
}
@@ -264,9 +270,11 @@ public class EditorView implements TextDrawingCallback, Disposable {
myMaxCharWidth = -1;
myTabSize = -1;
}
reset();
setPrefix(myPrefixText, myPrefixAttributes); // recreate prefix layout
myLogicalPositionCache.reset(false);
myTextLayoutCache.resetToDocumentSize(false);
invalidateFoldRegionLayouts();
setPrefix(myPrefixText, myPrefixAttributes); // recreate prefix layout
mySizeManager.reset();
}
public void invalidateRange(int startOffset, int endOffset) {
@@ -277,14 +285,18 @@ public class EditorView implements TextDrawingCallback, Disposable {
}
int startLine = myDocument.getLineNumber(Math.max(0, startOffset));
int endLine = myDocument.getLineNumber(Math.min(textLength, endOffset));
myTextLayoutCache.invalidateLines(startLine, endLine, endLine);
myTextLayoutCache.invalidateLines(startLine, endLine);
mySizeManager.invalidateRange(startOffset, endOffset);
}
/**
* Invoked when document might have changed, but no notifications were sent (for a hacky document in EditorTextFieldCellRenderer)
*/
public void reset() {
assertIsDispatchThread();
myLogicalPositionCache.reset(true);
myTextLayoutCache.resetToDocumentSize(true);
mySizeManager.reset();
myTextLayoutCache.resetToDocumentSize();
}
public boolean isRtlLocation(@NotNull VisualPosition visualPosition) {
@@ -422,8 +434,7 @@ public class EditorView implements TextDrawingCallback, Disposable {
if (layout == null) {
TextAttributes placeholderAttributes = myEditor.getFoldingModel().getPlaceholderAttributes();
layout = new LineLayout(this, foldRegion.getPlaceholderText(),
placeholderAttributes == null ? Font.PLAIN : placeholderAttributes.getFontType(),
myFontRenderContext);
placeholderAttributes == null ? Font.PLAIN : placeholderAttributes.getFontType());
foldRegion.putUserData(FOLD_REGION_TEXT_LAYOUT, layout);
}
return layout;
@@ -32,10 +32,6 @@ interface LineFragment {
int getLogicalColumnCount(int startColumn);
int getVisualColumnCount(float startX);
int offsetToLogicalColumn(int startColumn, int offset);
int logicalColumnToOffset(int startColumn, int column);
// columns are visual
int logicalToVisualColumn(float startX, int startColumn, int column);
@@ -35,100 +35,84 @@ import java.util.List;
/**
* Layout of a single line of document text. Consists of a series of BidiRuns, which, in turn, consist of TextFragments.
* TextFragments within BidiRun are grouped into Chunks for performance reasons, glyph layout is performed per-Chunk, and only
* for required Chunks.
*/
class LineLayout {
private final BidiRun[] myBidiRunsInLogicalOrder;
private final BidiRun[] myBidiRunsInVisualOrder;
private final float myWidth;
/**
* Creates a dummy layout used for editor size estimations
*/
LineLayout(EditorView view, int lineLength) {
this(createDummyFragment(view, lineLength), false);
}
/**
* Creates a layout for a fragment of text from editor.
*/
LineLayout(@NotNull EditorView view,
int startOffset, int endOffset,
@NotNull FontRenderContext fontRenderContext) {
this(createFragments(view, startOffset, endOffset, fontRenderContext), false);
LineLayout(@NotNull EditorView view, int startOffset, int endOffset, boolean skipBidiLayout) {
this(createFragments(view, startOffset, endOffset, skipBidiLayout), false);
}
/**
* Creates a layout for an arbitrary piece of text (using a common font style).
*/
LineLayout(@NotNull EditorView view,
@NotNull CharSequence text, @JdkConstants.FontStyle int fontStyle,
@NotNull FontRenderContext fontRenderContext) {
this(createFragments(view, text, fontStyle, fontRenderContext), true);
LineLayout(@NotNull EditorView view, @NotNull CharSequence text, @JdkConstants.FontStyle int fontStyle) {
this(createFragments(view, text, fontStyle), true);
}
private LineLayout(@NotNull List<BidiRun> runs, boolean calculateWidth) {
myBidiRunsInLogicalOrder = runs.toArray(new BidiRun[runs.size()]);
myBidiRunsInVisualOrder = myBidiRunsInLogicalOrder.clone();
reorderRunsVisually(myBidiRunsInVisualOrder);
int logicalColumn = 0;
for (BidiRun run : runs) {
logicalColumn = run.createIndices(logicalColumn);
}
reorderRunsVisually(myBidiRunsInVisualOrder);
myWidth = calculateWidth ? calculateWidth() : -1;
}
private static void reorderRunsVisually(BidiRun[] bidiRunsInLogicalOrder) {
if (bidiRunsInLogicalOrder.length > 1) {
byte[] levels = new byte[bidiRunsInLogicalOrder.length];
for (int i = 0; i < bidiRunsInLogicalOrder.length; i++) {
levels[i] = bidiRunsInLogicalOrder[i].level;
// runs are supposed to be in logical order initially
private static void reorderRunsVisually(BidiRun[] bidiRuns) {
if (bidiRuns.length > 1) {
byte[] levels = new byte[bidiRuns.length];
for (int i = 0; i < bidiRuns.length; i++) {
levels[i] = bidiRuns[i].level;
}
Bidi.reorderVisually(levels, 0, bidiRunsInLogicalOrder, 0, levels.length);
Bidi.reorderVisually(levels, 0, bidiRuns, 0, levels.length);
}
}
static boolean isBidiLayoutRequired(@NotNull CharSequence text) {
char[] chars = CharArrayUtil.fromSequence(text);
return Bidi.requiresBidi(chars, 0, chars.length);
}
private static List<BidiRun> createFragments(@NotNull EditorView view, int lineStartOffset, int lineEndOffset,
@NotNull FontRenderContext fontRenderContext) {
private static List<BidiRun> createFragments(@NotNull EditorView view, int lineStartOffset, int lineEndOffset, boolean skipBidiLayout) {
if (lineEndOffset <= lineStartOffset) return Collections.emptyList();
EditorImpl editor = view.getEditor();
FontPreferences fontPreferences = editor.getColorsScheme().getFontPreferences();
char[] chars = CharArrayUtil.fromSequence(editor.getDocument().getImmutableCharSequence(), lineStartOffset, lineEndOffset);
List<BidiRun> runs = createRuns(editor, chars, lineStartOffset);
for (BidiRun run : runs) {
IterationState it = new IterationState(editor, lineStartOffset + run.startOffset, lineStartOffset + run.endOffset,
false, false, false, false);
while (!it.atEnd()) {
addFragments(run, chars, it.getStartOffset() - lineStartOffset, it.getEndOffset() - lineStartOffset,
it.getMergedAttributes().getFontType(), fontPreferences, fontRenderContext, view.getTabFragment());
it.advance();
}
assert !run.fragments.isEmpty();
List<BidiRun> runs;
if (skipBidiLayout) {
runs = Collections.singletonList(new BidiRun((byte)0, 0, lineEndOffset - lineStartOffset));
}
else {
CharSequence text = editor.getDocument().getImmutableCharSequence().subSequence(lineStartOffset, lineEndOffset);
char[] chars = CharArrayUtil.fromSequence(text);
runs = createRuns(editor, chars, lineStartOffset);
}
return runs;
}
private static List<BidiRun> createFragments(@NotNull EditorView view, @NotNull CharSequence text,
@JdkConstants.FontStyle int fontStyle, @NotNull FontRenderContext fontRenderContext) {
@JdkConstants.FontStyle int fontStyle) {
if (text.length() == 0) return Collections.emptyList();
EditorImpl editor = view.getEditor();
FontRenderContext fontRenderContext = view.getFontRenderContext();
FontPreferences fontPreferences = editor.getColorsScheme().getFontPreferences();
char[] chars = CharArrayUtil.fromSequence(text);
List<BidiRun> runs = createRuns(editor, chars, -1);
for (BidiRun run : runs) {
addFragments(run, chars, run.startOffset, run.endOffset, fontStyle, fontPreferences, fontRenderContext, null);
assert !run.fragments.isEmpty();
for (Chunk chunk : run.getChunks()) {
addFragments(chunk, run.isRtl(), chars, chunk.startOffset, chunk.endOffset, fontStyle, fontPreferences, fontRenderContext, null);
}
}
return runs;
}
private static List<BidiRun> createDummyFragment(@NotNull EditorView view, int lineLength) {
BidiRun run = new BidiRun((byte)0, 0, lineLength);
run.fragments.add(new DummyLineFragment(lineLength, view.getMaxCharWidth()));
return Collections.singletonList(run);
}
private static List<BidiRun> createRuns(EditorImpl editor, char[] text, int startOffsetInEditor) {
int textLength = text.length;
if (editor.myDisableRtl) return Collections.singletonList(new BidiRun((byte)0, 0, textLength));
@@ -186,37 +170,39 @@ class LineLayout {
}
}
private static void addFragments(BidiRun run, char[] text, int start, int end, int fontStyle,
private static void addFragments(Chunk chunk, boolean isRtl, char[] text, int start, int end, int fontStyle,
FontPreferences fontPreferences, FontRenderContext fontRenderContext,
@Nullable TabFragment tabFragment) {
assert start < end;
Font currentFont = null;
int currentIndex = start;
for(int i = start; i < end; i++) {
char c = text[i];
if (c == '\t' && tabFragment != null) {
assert run.level == 0;
addTextFragmentIfNeeded(run, text, currentIndex, i, currentFont, fontRenderContext, run.isRtl());
run.fragments.add(tabFragment);
assert !isRtl;
addTextFragmentIfNeeded(chunk, text, currentIndex, i, currentFont, fontRenderContext, false);
chunk.fragments.add(tabFragment);
currentFont = null;
currentIndex = i + 1;
}
else {
Font font = ComplementaryFontsRegistry.getFontAbleToDisplay(c, fontStyle, fontPreferences).getFont();
if (!font.equals(currentFont)) {
addTextFragmentIfNeeded(run, text, currentIndex, i, currentFont, fontRenderContext, run.isRtl());
addTextFragmentIfNeeded(chunk, text, currentIndex, i, currentFont, fontRenderContext, isRtl);
currentFont = font;
currentIndex = i;
}
}
}
addTextFragmentIfNeeded(run, text, currentIndex, end, currentFont, fontRenderContext, run.isRtl());
addTextFragmentIfNeeded(chunk, text, currentIndex, end, currentFont, fontRenderContext, isRtl);
assert !chunk.fragments.isEmpty();
}
private static void addTextFragmentIfNeeded(BidiRun run, char[] chars, int from, int to, Font font,
private static void addTextFragmentIfNeeded(Chunk chunk, char[] chars, int from, int to, Font font,
FontRenderContext fontRenderContext, boolean isRtl) {
if (to > from) {
assert font != null;
run.fragments.add(new TextFragment(chars, from, to, isRtl, font, fontRenderContext));
chunk.fragments.add(new TextFragment(chars, from, to, isRtl, font, fontRenderContext));
}
}
@@ -233,38 +219,24 @@ class LineLayout {
return myWidth;
}
int offsetToLogicalColumn(int offset) {
if (offset <= 0) return 0;
for (BidiRun run : myBidiRunsInLogicalOrder) {
if (offset <= run.endOffset) return run.offsetToLogicalColumn(offset);
}
return myBidiRunsInLogicalOrder.length == 0 ? 0 : myBidiRunsInLogicalOrder[myBidiRunsInLogicalOrder.length - 1].endLogicalColumn;
}
int logicalColumnToOffset(int logicalColumn) {
if (logicalColumn <= 0) return 0;
for (BidiRun run : myBidiRunsInLogicalOrder) {
if (logicalColumn <= run.endLogicalColumn) return run.logicalColumnToOffset(logicalColumn);
}
return myBidiRunsInLogicalOrder.length == 0 ? 0 : myBidiRunsInLogicalOrder[myBidiRunsInLogicalOrder.length - 1].endOffset;
}
Iterable<VisualFragment> getFragmentsInVisualOrder(final float startX) {
return new Iterable<VisualFragment>() {
@Override
public Iterator<VisualFragment> iterator() {
return new VisualOrderIterator(startX, 0, 0, 0, myBidiRunsInVisualOrder);
return new VisualOrderIterator(null, 0, startX, 0, 0, 0, myBidiRunsInVisualOrder);
}
};
}
Iterable<VisualFragment> getFragmentsInVisualOrder(final float startX,
final int startVisualColumn,
final int startOffset,
int endOffset) {
Iterable<VisualFragment> getFragmentsInVisualOrder(@NotNull final EditorView view,
final int lineStartOffset,
final float startX,
final int startVisualColumn,
final int startOffset,
int endOffset,
boolean quick) {
assert startOffset <= endOffset;
final BidiRun[] runs;
int startLogicalColumn = 0;
if (startOffset == endOffset) {
runs = new BidiRun[0];
}
@@ -273,19 +245,16 @@ class LineLayout {
for (BidiRun run : myBidiRunsInLogicalOrder) {
if (run.endOffset <= startOffset) continue;
if (run.startOffset >= endOffset) break;
runList.add(run.subRun(startOffset, endOffset));
if (run.startOffset <= startOffset) {
startLogicalColumn = run.offsetToLogicalColumn(startOffset);
}
runList.add(run.subRun(view, lineStartOffset, startOffset, endOffset, quick));
}
runs = runList.toArray(new BidiRun[runList.size()]);
reorderRunsVisually(runs);
}
final int finalStartLogicalColumn = startLogicalColumn;
final int startLogicalColumn = view.offsetToLogicalPosition(lineStartOffset + startOffset).column;
return new Iterable<VisualFragment>() {
@Override
public Iterator<VisualFragment> iterator() {
return new VisualOrderIterator(startX, startVisualColumn, finalStartLogicalColumn, startOffset, runs);
return new VisualOrderIterator(view, lineStartOffset, startX, startVisualColumn, startLogicalColumn, startOffset, runs);
}
};
}
@@ -332,17 +301,12 @@ class LineLayout {
}
private static class BidiRun {
private static final int CHUNK_CHARACTERS = 1024;
private final byte level;
private final int startOffset;
private final int endOffset;
private final List<LineFragment> fragments = new ArrayList<LineFragment>(); // in logical order
// values cached for performance
private static final int INDEX_FREQUENCY = 100;
private int startLogicalColumn;
private int endLogicalColumn;
private int[] offsetIndex; // stores start offsets for each INDEX_FREQUENCY-th fragment, for faster lookup by offset
private int[] logicalColumnIndex; // stores start logical column for each INDEX_FREQUENCY-th fragment, for faster offset <-> logical column conversions
private Chunk[] chunks; // in logical order
private BidiRun(byte level, int startOffset, int endOffset) {
this.level = level;
@@ -353,124 +317,108 @@ class LineLayout {
private boolean isRtl() {
return (level & 1) != 0;
}
private BidiRun subRun(int targetStartOffset, int targetEndOffset) {
assert targetStartOffset < endOffset;
assert targetEndOffset > startOffset;
if (targetStartOffset <= startOffset && targetEndOffset >= this.endOffset) {
return this;
}
int start = Math.max(startOffset, targetStartOffset);
int end = Math.min(endOffset, targetEndOffset);
BidiRun run = new BidiRun(level, start, end);
int offset = startOffset;
int startFragment = 0;
if (offsetIndex != null) {
int pos = Arrays.binarySearch(offsetIndex, start);
if (pos < 0) pos = - pos - 2;
if (pos >= 0) {
startFragment = (pos + 1) * INDEX_FREQUENCY;
offset = offsetIndex[pos];
private Chunk[] getChunks() {
if (chunks == null) {
int chunkCount = (endOffset - startOffset + CHUNK_CHARACTERS - 1) / CHUNK_CHARACTERS;
chunks = new Chunk[chunkCount];
for (int i = 0; i < chunkCount; i++) {
int from = startOffset + i * CHUNK_CHARACTERS;
int to = (i == chunkCount - 1) ? endOffset : from + CHUNK_CHARACTERS;
Chunk chunk = new Chunk(from, to);
chunks[i] = chunk;
}
}
for (int i = startFragment; i < fragments.size(); i++) {
LineFragment fragment = fragments.get(i);
return chunks;
}
private BidiRun subRun(@NotNull EditorView view, int lineStartOffset, int targetStartOffset, int targetEndOffset, boolean quick) {
assert targetStartOffset < endOffset;
assert targetEndOffset > startOffset;
int start = Math.max(startOffset, targetStartOffset);
int end = Math.min(endOffset, targetEndOffset);
BidiRun subRun = new BidiRun(level, start, end);
List<Chunk> subChunks = new ArrayList<Chunk>();
for (Chunk chunk : getChunks()) {
if (chunk.endOffset <= start) continue;
if (chunk.startOffset >= end) break;
subChunks.add(chunk.subChunk(view, lineStartOffset, isRtl(), start, end, quick));
}
subRun.chunks = subChunks.toArray(new Chunk[subChunks.size()]);
return subRun;
}
}
private static class Chunk {
private final List<LineFragment> fragments = new ArrayList<LineFragment>(); // in logical order
private int startOffset;
private int endOffset;
private Chunk(int startOffset, int endOffset) {
this.startOffset = startOffset;
this.endOffset = endOffset;
}
private void ensureLayout(@NotNull EditorView view, int lineStartOffset, boolean isRtl) {
if (!fragments.isEmpty()) return;
int start = lineStartOffset + startOffset;
int end = lineStartOffset + endOffset;
IterationState it = new IterationState(view.getEditor(), start, end, false, false, false, false);
FontPreferences fontPreferences = view.getEditor().getColorsScheme().getFontPreferences();
char[] chars = CharArrayUtil.fromSequence(view.getEditor().getDocument().getImmutableCharSequence(), start, end);
while (!it.atEnd()) {
addFragments(this, isRtl, chars, it.getStartOffset() - start, it.getEndOffset() - start,
it.getMergedAttributes().getFontType(), fontPreferences, view.getFontRenderContext(), view.getTabFragment());
it.advance();
}
view.getSizeManager().textLayoutPerformed(start, end);
assert !fragments.isEmpty();
}
private Chunk subChunk(EditorView view, int lineStartOffset, boolean isRtl, int targetStartOffset, int targetEndOffset, boolean quick) {
assert targetStartOffset < endOffset;
assert targetEndOffset > startOffset;
int start = Math.max(startOffset, targetStartOffset);
int end = Math.min(endOffset, targetEndOffset);
if (quick && fragments.isEmpty()) {
Chunk chunk = new Chunk(start, end);
int startColumn = view.offsetToLogicalPosition(lineStartOffset + start).column;
int endColumn = view.offsetToLogicalPosition(lineStartOffset + end).column;
chunk.fragments.add(new ApproximationFragment(end - start, endColumn - startColumn, view.getMaxCharWidth()));
return chunk;
}
if (start == startOffset && end == this.endOffset) {
return this;
}
ensureLayout(view, lineStartOffset, isRtl);
Chunk chunk = new Chunk(start, end);
int offset = startOffset;
for (LineFragment fragment : fragments) {
if (end <= offset) break;
int endOffset = offset + fragment.getLength();
if (start < endOffset) {
run.fragments.add(fragment.subFragment(Math.max(start, offset) - offset, Math.min(end, endOffset) - offset));
chunk.fragments.add(fragment.subFragment(Math.max(start, offset) - offset, Math.min(end, endOffset) - offset));
}
offset = endOffset;
}
return run;
}
private int logicalColumnToOffset(int logicalColumn) {
if (logicalColumn <= startLogicalColumn) return startOffset;
if (logicalColumn >= endLogicalColumn) return endOffset;
int currentOffset = startOffset;
int currentLogicalColumn = startLogicalColumn;
int startFragment = 0;
if (offsetIndex != null) {
int pos = Arrays.binarySearch(logicalColumnIndex == null ? offsetIndex : logicalColumnIndex, logicalColumn);
if (pos >= 0) return offsetIndex[pos];
int beforeInsertPosition = - pos - 2;
currentOffset = beforeInsertPosition < 0 ? startOffset : offsetIndex[beforeInsertPosition];
currentLogicalColumn = beforeInsertPosition < 0 ? startLogicalColumn : logicalColumnIndex == null ? currentOffset :
logicalColumnIndex[beforeInsertPosition];
startFragment = INDEX_FREQUENCY * (beforeInsertPosition + 1);
}
for (int i = startFragment; i < fragments.size(); i++) {
LineFragment fragment = fragments.get(i);
int endLogicalColumn = currentLogicalColumn + fragment.getLogicalColumnCount(currentLogicalColumn);
if (logicalColumn <= endLogicalColumn) return currentOffset + fragment.logicalColumnToOffset(currentLogicalColumn, logicalColumn);
currentOffset += fragment.getLength();
currentLogicalColumn = endLogicalColumn;
}
throw new IllegalStateException();
}
private int offsetToLogicalColumn(int offset) {
if (offset <= startOffset) return startLogicalColumn;
if (offset >= endOffset) return endLogicalColumn;
int currentOffset = startOffset;
int currentLogicalColumn = startLogicalColumn;
int startFragment = 0;
if (offsetIndex != null) {
int pos = Arrays.binarySearch(offsetIndex, offset);
if (pos >= 0) return logicalColumnIndex == null ? offset : logicalColumnIndex[pos];
int beforeInsertPosition = - pos - 2;
currentOffset = beforeInsertPosition < 0 ? startOffset : offsetIndex[beforeInsertPosition];
currentLogicalColumn = beforeInsertPosition < 0 ? startLogicalColumn : logicalColumnIndex == null ? currentOffset :
logicalColumnIndex[beforeInsertPosition];
startFragment = INDEX_FREQUENCY * (beforeInsertPosition + 1);
}
for (int i = startFragment; i < fragments.size(); i++) {
LineFragment fragment = fragments.get(i);
int endOffset = currentOffset + fragment.getLength();
if (offset <= endOffset) return fragment.offsetToLogicalColumn(currentLogicalColumn, offset - currentOffset);
currentOffset = endOffset;
currentLogicalColumn += fragment.getLogicalColumnCount(currentLogicalColumn);
}
throw new IllegalStateException();
}
private int createIndices(int startLogicalColumn) {
this.startLogicalColumn = endLogicalColumn = startLogicalColumn;
int indexSize = (fragments.size() - 1) / INDEX_FREQUENCY;
if (indexSize > 0) {
offsetIndex = new int[indexSize];
}
int i = 0;
int offset = startOffset;
for (LineFragment fragment : fragments) {
if (offsetIndex != null && i > 0 && (i % INDEX_FREQUENCY) == 0) {
int pos = i / INDEX_FREQUENCY - 1;
offsetIndex[pos] = offset;
if (logicalColumnIndex == null && offset != endLogicalColumn) {
logicalColumnIndex = new int[indexSize];
System.arraycopy(offsetIndex, 0, logicalColumnIndex, 0, pos);
}
if (logicalColumnIndex != null) {
logicalColumnIndex[pos] = endLogicalColumn;
}
}
i++;
offset += fragment.getLength();
endLogicalColumn += fragment.getLogicalColumnCount(endLogicalColumn);
}
return endLogicalColumn;
return chunk;
}
}
private static class VisualOrderIterator implements Iterator<VisualFragment> {
private BidiRun[] myRuns;
private final EditorView myView;
private final int myLineStartOffset;
private final BidiRun[] myRuns;
private int myRunIndex = 0;
private int myChunkIndex = 0;
private int myFragmentIndex = 0;
private int myOffsetInsideRun = 0;
private VisualFragment myFragment = new VisualFragment();
private VisualOrderIterator(float startX, int startVisualColumn, int startLogicalColumn, int startOffset, BidiRun[] runsInVisualOrder) {
private VisualOrderIterator(EditorView view, int lineStartOffset,
float startX, int startVisualColumn, int startLogicalColumn, int startOffset, BidiRun[] runsInVisualOrder) {
myView = view;
myLineStartOffset = lineStartOffset;
myRuns = runsInVisualOrder;
myFragment.startX = startX;
myFragment.startVisualColumn = startVisualColumn;
@@ -480,7 +428,15 @@ class LineLayout {
@Override
public boolean hasNext() {
return myRunIndex < myRuns.length && myFragmentIndex < myRuns[myRunIndex].fragments.size();
if (myRunIndex >= myRuns.length) return false;
BidiRun run = myRuns[myRunIndex];
Chunk[] chunks = run.getChunks();
if (myChunkIndex >= chunks.length) return false;
Chunk chunk = chunks[run.isRtl() ? chunks.length - 1 - myChunkIndex : myChunkIndex];
if (myView != null) {
chunk.ensureLayout(myView, myLineStartOffset, run.isRtl());
}
return myFragmentIndex < chunk.fragments.size();
}
@Override
@@ -490,12 +446,12 @@ class LineLayout {
}
BidiRun run = myRuns[myRunIndex];
if (myRunIndex == 0 && myFragmentIndex == 0) {
if (myRunIndex == 0 && myChunkIndex == 0 && myFragmentIndex == 0) {
myFragment.startLogicalColumn += (run.isRtl() ? run.endOffset : run.startOffset) - myFragment.startOffset;
}
else {
myFragment.startLogicalColumn = myFragment.getEndLogicalColumn();
if (myFragmentIndex == 0) {
if (myChunkIndex == 0 && myFragmentIndex == 0) {
myFragment.startLogicalColumn += (run.isRtl() ? run.endOffset : run.startOffset) - myFragment.getEndOffset();
}
myFragment.startVisualColumn = myFragment.getEndVisualColumn();
@@ -503,15 +459,22 @@ class LineLayout {
}
myFragment.isRtl = run.isRtl();
myFragment.delegate = run.fragments.get(run.isRtl() ? run.fragments.size() - 1 - myFragmentIndex : myFragmentIndex);
Chunk[] chunks = run.getChunks();
Chunk chunk = chunks[run.isRtl() ? chunks.length - 1 - myChunkIndex : myChunkIndex];
assert !chunk.fragments.isEmpty();
myFragment.delegate = chunk.fragments.get(run.isRtl() ? chunk.fragments.size() - 1 - myFragmentIndex : myFragmentIndex);
myFragment.startOffset = run.isRtl() ? run.endOffset - myOffsetInsideRun : run.startOffset + myOffsetInsideRun;
myOffsetInsideRun += myFragment.getLength();
myFragmentIndex++;
if (myFragmentIndex >= run.fragments.size()) {
if (myFragmentIndex >= chunk.fragments.size()) {
myFragmentIndex = 0;
myOffsetInsideRun = 0;
myRunIndex++;
myChunkIndex++;
if (myChunkIndex >= chunks.length) {
myChunkIndex = 0;
myOffsetInsideRun = 0;
myRunIndex++;
}
}
return myFragment;
@@ -649,77 +612,4 @@ class LineLayout {
return isRtl ? startOffset - offset : offset - startOffset;
}
}
public static class DummyLineFragment implements LineFragment {
private final int myLength;
private final float myCharWidth;
public DummyLineFragment(int length, float charWidth) {
myLength = length;
myCharWidth = charWidth;
}
@Override
public int getLength() {
return myLength;
}
@Override
public int getLogicalColumnCount(int startColumn) {
return myLength;
}
@Override
public int getVisualColumnCount(float startX) {
return myLength;
}
@Override
public int offsetToLogicalColumn(int startColumn, int offset) {
return startColumn + offset;
}
@Override
public int logicalColumnToOffset(int startColumn, int column) {
return column - startColumn;
}
@Override
public int logicalToVisualColumn(float startX, int startColumn, int column) {
return column;
}
@Override
public int visualToLogicalColumn(float startX, int startColumn, int column) {
return column;
}
@Override
public float visualColumnToX(float startX, int column) {
return column * myCharWidth;
}
@Override
public int[] xToVisualColumn(float startX, float x) {
float relX = x - startX;
int column = Math.max(0, Math.min(myLength, Math.round(relX / myCharWidth)));
return new int[] {column, relX <= column * myCharWidth ? 0 : 1};
}
@Override
public float offsetToX(float startX, int startOffset, int offset) {
return offset * myCharWidth;
}
@Override
public void draw(Graphics2D g, float x, float y, int startColumn, int endColumn) {
throw new UnsupportedOperationException();
}
@NotNull
@Override
public LineFragment subFragment(int startOffset, int endOffset) {
return new DummyLineFragment(endOffset - startOffset, myCharWidth);
}
}
}
@@ -0,0 +1,205 @@
/*
* Copyright 2000-2015 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.openapi.editor.impl.view;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.ex.PrioritizedDocumentListener;
import com.intellij.openapi.editor.impl.EditorDocumentPriorities;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
/**
* Caches information allowing faster offset<->logicalPosition conversions even for long lines.
* Requests for conversion can be made from under read action, document changes and cache invalidation should be done in EDT.
*/
@SuppressWarnings("SynchronizeOnThis")
class LogicalPositionCache implements PrioritizedDocumentListener, Disposable {
private final Document myDocument;
private final EditorView myView;
private ArrayList<LineData> myLines = new ArrayList<LineData>();
private int myTabSize = -1;
private int myDocumentChangeOldEndLine;
LogicalPositionCache(EditorView view) {
myView = view;
myDocument = view.getEditor().getDocument();
myDocument.addDocumentListener(this, this);
}
@Override
public int getPriority() {
return EditorDocumentPriorities.LOGICAL_POSITION_CACHE;
}
@Override
public void beforeDocumentChange(DocumentEvent event) {
myDocumentChangeOldEndLine = getAdjustedLineNumber(event.getOffset() + event.getOldLength());
}
@Override
public void documentChanged(DocumentEvent event) {
int startLine = myDocument.getLineNumber(event.getOffset());
int newEndLine = getAdjustedLineNumber(event.getOffset() + event.getNewLength());
invalidateLines(startLine, myDocumentChangeOldEndLine, newEndLine, CharArrayUtil.indexOf(event.getNewFragment(), "\t", 0) == -1);
}
synchronized void reset(boolean force) {
checkDisposed();
int oldTabSize = myTabSize;
myTabSize = myView.getTabSize();
if (force || oldTabSize != myTabSize) {
invalidateLines(0, myLines.size() - 1, myDocument.getLineCount() - 1, true);
}
}
@NotNull
synchronized LogicalPosition offsetToLogicalPosition(int offset) {
int textLength = myDocument.getTextLength();
if (offset <= 0 || textLength == 0) {
return new LogicalPosition(0, 0);
}
offset = Math.min(offset, textLength);
int line = myDocument.getLineNumber(offset);
LineData lineData = getLineInfo(line);
return new LogicalPosition(line, lineData.offsetToLogicalColumn(myDocument, line, myTabSize, offset));
}
synchronized int logicalPositionToOffset(@NotNull LogicalPosition pos) {
int line = pos.line;
if (line >= myDocument.getLineCount()) return myDocument.getTextLength();
LineData lineData = getLineInfo(line);
return lineData.logicalColumnToOffset(myDocument, line, myTabSize, pos.column);
}
private int getAdjustedLineNumber(int offset) {
return myDocument.getTextLength() == 0 ? -1 : myDocument.getLineNumber(offset);
}
private synchronized void invalidateLines(int startLine, int oldEndLine, int newEndLine, boolean preserveTrivialLines) {
checkDisposed();
int endLine = Math.min(oldEndLine, newEndLine);
for (int line = startLine; line <= endLine; line++) {
LineData data = myLines.get(line);
if (data != null && (!preserveTrivialLines || data.columnCache != null)) myLines.set(line, null);
}
if (oldEndLine < newEndLine) {
myLines.addAll(oldEndLine + 1, Collections.nCopies(newEndLine - oldEndLine, (LineData)null));
} else if (oldEndLine > newEndLine) {
myLines.subList(newEndLine + 1, oldEndLine + 1).clear();
}
}
@NotNull
private LineData getLineInfo(int line) {
checkDisposed();
LineData result = myLines.get(line);
if (result == null) {
result = new LineData(myDocument, line, myTabSize);
myLines.set(line, result);
}
return result;
}
@Override
public synchronized void dispose() {
myLines = null;
}
private void checkDisposed() {
if (myLines == null) throw new IllegalStateException("Editor is already disposed");
}
private static class LineData {
private static final int CACHE_FREQUENCY = 1024; // logical column will be cached for each CACHE_FREQUENCY-th character on the line
private final int[] columnCache;
private LineData(@NotNull Document document, int line, int tabSize) {
int start = document.getLineStartOffset(line);
int end = document.getLineEndOffset(line);
int cacheSize = (end - start) / CACHE_FREQUENCY;
int[] cache = new int[cacheSize];
CharSequence text = document.getImmutableCharSequence();
int column = 0;
boolean hasTabs = false;
for (int i = start; i < end; i++) {
if (i > start && (i - start) % CACHE_FREQUENCY == 0) {
cache[(i - start) / CACHE_FREQUENCY - 1] = column;
}
if (text.charAt(i) == '\t') {
column = (column / tabSize + 1) * tabSize;
hasTabs = true;
}
else {
column++;
}
}
columnCache = hasTabs ? cache : null;
}
private int offsetToLogicalColumn(@NotNull Document document, int line, int tabSize, int offset) {
offset = Math.min(offset, document.getLineEndOffset(line));
int lineStartOffset = document.getLineStartOffset(line);
int relOffset = offset - lineStartOffset;
if (columnCache == null) return relOffset;
int cacheIndex = relOffset / CACHE_FREQUENCY;
int startOffset = lineStartOffset + cacheIndex * CACHE_FREQUENCY;
int column = cacheIndex == 0 ? 0 : columnCache[cacheIndex - 1];
CharSequence text = document.getImmutableCharSequence();
for (int i = startOffset; i < offset; i++) {
if (text.charAt(i) == '\t') {
column = (column / tabSize + 1) * tabSize;
}
else {
column++;
}
}
return column;
}
private int logicalColumnToOffset(@NotNull Document document, int line, int tabSize, int logicalColumn) {
int lineStartOffset = document.getLineStartOffset(line);
int lineEndOffset = document.getLineEndOffset(line);
if (columnCache == null) {
int result = lineStartOffset + logicalColumn;
return result < 0 || // guarding over overflow
result > lineEndOffset ? lineEndOffset : result;
}
int pos = Arrays.binarySearch(columnCache, logicalColumn);
if (pos >= 0) return lineStartOffset + (pos + 1) * CACHE_FREQUENCY;
int startOffset = lineStartOffset + (- pos - 1) * CACHE_FREQUENCY;
int column = pos == -1 ? 0 : columnCache[- pos - 2];
CharSequence text = document.getImmutableCharSequence();
for (int i = startOffset; i < lineEndOffset; i++) {
if (text.charAt(i) == '\t') {
column = (column / tabSize + 1) * tabSize;
}
else {
column++;
}
if (logicalColumn < column) return i;
}
return lineEndOffset;
}
}
}
@@ -50,16 +50,6 @@ class TabFragment implements LineFragment {
return EditorUtil.columnsNumber((int)(x - startX), myView.getPlainSpaceWidth());
}
@Override
public int offsetToLogicalColumn(int startColumn, int offset) {
return startColumn + (offset == 0 ? 0 : getLogicalColumnCount(startColumn));
}
@Override
public int logicalColumnToOffset(int startColumn, int column) {
return column < (startColumn + getLogicalColumnCount(startColumn)) ? 0 : 1;
}
@Override
public void draw(Graphics2D g, float x, float y, int startColumn, int endColumn) {
}
@@ -72,16 +72,6 @@ class TextFragment implements LineFragment {
return myCharPositions.length;
}
@Override
public int offsetToLogicalColumn(int startColumn, int offset) {
return startColumn + offset;
}
@Override
public int logicalColumnToOffset(int startColumn, int column) {
return column - startColumn;
}
@Override
public void draw(Graphics2D g, float x, float y, int startColumn, int endColumn) {
assert startColumn >= 0;
@@ -201,16 +191,6 @@ class TextFragment implements LineFragment {
return getLength();
}
@Override
public int offsetToLogicalColumn(int startColumn, int offset) {
return startColumn + offset;
}
@Override
public int logicalColumnToOffset(int startColumn, int column) {
return column - startColumn;
}
@Override
public int logicalToVisualColumn(float startX, int startColumn, int column) {
return column;
@@ -22,24 +22,28 @@ import com.intellij.openapi.editor.ex.PrioritizedDocumentListener;
import com.intellij.openapi.editor.impl.EditorDocumentPriorities;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
/**
* Editor text layout storage. It's cached on a per-line basis, created lazily (when requested), and invalidated on document changes or
* when explicitly requested.
* Editor text layout storage. Layout is stored on a per-logical-line basis,
* it's created lazily (when requested) and invalidated on document changes or when explicitly requested.
*
* @see LineLayout
*/
class TextLayoutCache implements PrioritizedDocumentListener, Disposable {
private final EditorView myView;
private final Document myDocument;
private final LineLayout myBidiNotRequiredMarker;
private ArrayList<LineLayout> myLines = new ArrayList<LineLayout>();
private int myDocumentChangeOldEndLine;
private boolean myQuickLayoutsEnabled;
TextLayoutCache(EditorView view) {
myView = view;
myDocument = view.getEditor().getDocument();
myDocument.addDocumentListener(this, this);
myBidiNotRequiredMarker = new LineLayout(view, "", Font.PLAIN);
}
@Override
@@ -56,7 +60,7 @@ class TextLayoutCache implements PrioritizedDocumentListener, Disposable {
public void documentChanged(DocumentEvent event) {
int startLine = myDocument.getLineNumber(event.getOffset());
int newEndLine = getAdjustedLineNumber(event.getOffset() + event.getNewLength());
invalidateLines(startLine, myDocumentChangeOldEndLine, newEndLine);
invalidateLines(startLine, myDocumentChangeOldEndLine, newEndLine, !LineLayout.isBidiLayoutRequired(event.getNewFragment()));
}
@Override
@@ -67,17 +71,24 @@ class TextLayoutCache implements PrioritizedDocumentListener, Disposable {
private int getAdjustedLineNumber(int offset) {
return myDocument.getTextLength() == 0 ? -1 : myDocument.getLineNumber(offset);
}
void resetToDocumentSize() {
void resetToDocumentSize(boolean documentChangedWithoutNotification) {
checkDisposed();
invalidateLines(0, myLines.size() - 1, myDocument.getLineCount() - 1);
invalidateLines(0, myLines.size() - 1, myDocument.getLineCount() - 1, !documentChangedWithoutNotification);
}
void invalidateLines(int startLine, int endLine) {
invalidateLines(startLine, endLine, endLine, true);
}
void invalidateLines(int startLine, int oldEndLine, int newEndLine) {
private void invalidateLines(int startLine, int oldEndLine, int newEndLine, boolean keepBidiNotRequiredState) {
checkDisposed();
int endLine = Math.min(oldEndLine, newEndLine);
for (int line = startLine; line <= endLine; line++) {
myLines.set(line, null);
LineLayout lineLayout = myLines.get(line);
if (lineLayout != null) {
myLines.set(line, keepBidiNotRequiredState && lineLayout.isLtr() ? myBidiNotRequiredMarker : null);
}
}
if (oldEndLine < newEndLine) {
myLines.addAll(oldEndLine + 1, Collections.nCopies(newEndLine - oldEndLine, (LineLayout)null));
@@ -85,31 +96,25 @@ class TextLayoutCache implements PrioritizedDocumentListener, Disposable {
myLines.subList(newEndLine + 1, oldEndLine + 1).clear();
}
}
@NotNull
LineLayout getLineLayout(int line) {
checkDisposed();
LineLayout result = myLines.get(line);
if (result == null) {
int lineStart = myDocument.getLineStartOffset(line);
int lineEnd = myDocument.getLineEndOffset(line);
if (myQuickLayoutsEnabled) {
result = new LineLayout(myView, lineEnd - lineStart);
myView.getSizeManager().quickLineLayoutCreated();
}
else {
result = new LineLayout(myView, lineStart, lineEnd, myView.getFontRenderContext());
myLines.set(line, result);
myView.getSizeManager().lineLayoutCreated(line);
}
if (result == null || result == myBidiNotRequiredMarker) {
result = createLineLayout(line, result == myBidiNotRequiredMarker);
myLines.set(line, result);
}
return result;
}
void enableQuickLayouts(boolean enabled) {
myQuickLayoutsEnabled = enabled;
@NotNull
private LineLayout createLineLayout(int line, boolean skipBidiLayout) {
int lineStart = myDocument.getLineStartOffset(line);
int lineEnd = myDocument.getLineEndOffset(line);
return new LineLayout(myView, lineStart, lineEnd, skipBidiLayout);
}
private void checkDisposed() {
if (myLines == null) throw new IllegalStateException("Editor is already disposed");
}
@@ -34,11 +34,11 @@ import java.util.NoSuchElementException;
*/
class VisualLineFragmentsIterator implements Iterator<VisualLineFragmentsIterator.Fragment> {
static Iterable<Fragment> create(final EditorView view, final int offset, final boolean beforeSoftWrap) {
static Iterable<Fragment> create(final EditorView view, final int offset, final boolean beforeSoftWrap, final boolean quick) {
return new Iterable<Fragment>() {
@Override
public Iterator<Fragment> iterator() {
return new VisualLineFragmentsIterator(view, offset, beforeSoftWrap);
return new VisualLineFragmentsIterator(view, offset, beforeSoftWrap, quick);
}
};
}
@@ -48,6 +48,7 @@ class VisualLineFragmentsIterator implements Iterator<VisualLineFragmentsIterato
private final FoldRegion[] myRegions;
private final Fragment myFragment = new Fragment();
private final int myVisualLineStartOffset;
private final boolean myQuick;
private int mySegmentStartOffset;
private int mySegmentEndOffset;
@@ -61,7 +62,8 @@ class VisualLineFragmentsIterator implements Iterator<VisualLineFragmentsIterato
private int myCurrentEndLogicalLine;
private int myNextWrapOffset;
private VisualLineFragmentsIterator(EditorView view, int offset, boolean beforeSoftWrap) {
private VisualLineFragmentsIterator(EditorView view, int offset, boolean beforeSoftWrap, boolean quick) {
myQuick = quick;
myView = view;
EditorImpl editor = view.getEditor();
myDocument = editor.getDocument();
@@ -108,9 +110,9 @@ class VisualLineFragmentsIterator implements Iterator<VisualLineFragmentsIterato
int line = myDocument.getLineNumber(mySegmentStartOffset);
mySegmentEndOffset = Math.min(myNextWrapOffset, Math.min(mySegmentEndOffset, myDocument.getLineEndOffset(line)));
int lineStartOffset = myDocument.getLineStartOffset(line);
myFragmentIterator = myView.getTextLayoutCache().getLineLayout(line).getFragmentsInVisualOrder(myCurrentX, myCurrentVisualColumn,
mySegmentStartOffset - lineStartOffset,
mySegmentEndOffset - lineStartOffset).iterator();
myFragmentIterator = myView.getTextLayoutCache().getLineLayout(line).
getFragmentsInVisualOrder(myView, lineStartOffset, myCurrentX, myCurrentVisualColumn,
mySegmentStartOffset - lineStartOffset, mySegmentEndOffset - lineStartOffset, myQuick).iterator();
}
}
@@ -0,0 +1,90 @@
/*
* Copyright 2000-2015 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.openapi.options;
import com.intellij.openapi.extensions.AbstractExtensionPointBean;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.util.LazyInstance;
import com.intellij.util.xmlb.annotations.Attribute;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Extension point for schemes exporters.
*
* @author Rustam Vishnyakov
*/
public class SchemeExporterEP <S extends Scheme> extends AbstractExtensionPointBean {
public static final ExtensionPointName<SchemeExporterEP> EP_NAME = ExtensionPointName.create("com.intellij.schemeExporter");
@Attribute("name")
public String name;
@Attribute("schemeClass")
public String schemeClass;
@Attribute("implementationClass")
public String implementationClass;
private final LazyInstance<SchemeExporter<S>> myExporterInstance = new LazyInstance<SchemeExporter<S>>() {
@Override
protected Class<SchemeExporter<S>> getInstanceClass() throws ClassNotFoundException {
return findClass(implementationClass);
}
};
public SchemeExporter<S> getInstance() {
return myExporterInstance.getValue();
}
/**
* Finds extensions supporting the given <code>schemeClass</code>
* @param schemeClass The class of the scheme to search extensions for.
* @return A collection of exporters capable of exporting schemes of the given class. An empty collection is returned if there are
* no matching exporters.
*/
@NotNull
public static <S extends Scheme> Collection<SchemeExporterEP<S>> getExtensions(Class<S> schemeClass) {
List<SchemeExporterEP<S>> exporters = new ArrayList<SchemeExporterEP<S>>();
for (SchemeExporterEP<?> exporterEP : EP_NAME.getExtensions()) {
if (schemeClass.getName().equals(exporterEP.schemeClass)) {
//noinspection unchecked
exporters.add((SchemeExporterEP<S>)exporterEP);
}
}
return exporters;
}
/**
* Find an exporter for the given name and scheme class. It is allowed for exporters to have the same name but different scheme classes.
* @param name The exporter name as defined in plug-in configuration.
* @param schemeClass The scheme class the exporter has to support.
* @return The found exporter or null if there are no exporters for the given name and scheme class.
*/
@Nullable
public static <S extends Scheme> SchemeExporter<S> getExporter(@NotNull String name, Class<S> schemeClass) {
for (SchemeExporterEP<S> exporterEP : getExtensions(schemeClass)) {
if (name.equals(exporterEP.name)) {
return exporterEP.getInstance();
}
}
return null;
}
}
@@ -18,6 +18,7 @@ package com.intellij.openapi.ui.impl;
import com.intellij.ide.DataManager;
import com.intellij.ide.IdeEventQueue;
import com.intellij.ide.impl.TypeSafeDataProviderAdapter;
import com.intellij.ide.ui.AntialiasingType;
import com.intellij.ide.ui.UISettings;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.Application;
@@ -57,6 +58,7 @@ import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import sun.swing.SwingUtilities2;
import javax.swing.*;
import java.awt.*;
@@ -955,12 +957,15 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
}
@Override
public void windowOpened(WindowEvent e) {
public void windowOpened(final WindowEvent e) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
myOpened = true;
final DialogWrapper activeWrapper = getActiveWrapper();
for (JComponent c : UIUtil.uiTraverser(e.getWindow()).filter(JComponent.class)) {
c.putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY, AntialiasingType.getAAHintForSwingComponent());
}
if (activeWrapper == null) {
myFocusedCallback.setRejected();
myTypeAheadDone.setRejected();
@@ -34,5 +34,5 @@ package com.intellij.openapi.util
* Put here extension functions and variables for classes from util/util-rt modules
*/
operator fun <A, B> Pair<A, B>.component1() = this.first
operator fun <A, B> Pair<A, B>.component2() = this.second
/*operator*/ fun <A, B> Pair<A, B>.component1() = this.first
/*operator*/ fun <A, B> Pair<A, B>.component2() = this.second
@@ -168,11 +168,11 @@ public class NativeFileWatcherImpl extends PluggableFileWatcher {
@Nullable
private static String getExecutableName(final boolean withSubDir) {
if (SystemInfo.isWindows) return (withSubDir ? "win" + File.separator : "") + "fsnotifier.exe";
else if (SystemInfo.isMac) return (withSubDir ? "mac" + File.separator : "") + "fsnotifier";
else if (SystemInfo.isLinux) return (withSubDir ? "linux" + File.separator : "") +
("arm".equals(SystemInfo.OS_ARCH) ? (SystemInfo.is32Bit ? "fsnotifier-arm" : null)
: (SystemInfo.isAMD64 ? "fsnotifier64" : "fsnotifier"));
if (SystemInfo.isWindows) return (withSubDir ? "win" + File.separator : "") + (SystemInfo.isAMD64 ? "fsnotifier64.exe" : "fsnotifier.exe");
if (SystemInfo.isMac) return (withSubDir ? "mac" + File.separator : "") + "fsnotifier";
if (SystemInfo.isLinux) return (withSubDir ? "linux" + File.separator : "") +
("arm".equals(SystemInfo.OS_ARCH) ? (SystemInfo.is32Bit ? "fsnotifier-arm" : null)
: (SystemInfo.isAMD64 ? "fsnotifier64" : "fsnotifier"));
return null;
}
@@ -5,6 +5,6 @@
<title>#[[$Title$]]#</title>
</head>
<body>
#[[$END$]]#
</body>
</html>
@@ -483,7 +483,7 @@ checkbox.keep.empty.throws.tags=Keep empty @throws tags
checkbox.enable.leading.asterisks=Enable leading asterisks
checkbox.use.throws.rather.than.exception=Use @throws rather than @exception
checkbox.wrap.at.right.margin=Wrap at right margin
checkbox.generate.p.on.empty.lines=Generate "<p/>" on empty lines
checkbox.generate.p.on.empty.lines=Generate "<p>" on empty lines
checkbox.keep.empty.lines=Keep empty lines
checkbox.do.not.wrap.one.line.comments=Do not wrap one line comments
checkbox.preserve.line.feeds=Preserve line feeds
@@ -506,6 +506,11 @@ message.code.style.scheme.already.exists=Scheme {0} already exists. Overwrite se
code.style.scheme.import.unnamed=Unnamed
message.code.style.scheme.import.success={0} settings were imported to {1} scheme.{2}
message.code.style.scheme.import.failure={0} import failed with error message: {1}
code.style.scheme.exporter.ui.export.as.title=Export As
code.style.scheme.exporter.ui.file.chooser.title=Target File
code.style.scheme.exporter.ui.file.chooser.message=Export to
code.style.scheme.exporter.ui.code.style.exported.message={0} code style exported to {1}
code.style.scheme.exporter.ui.cannot.write.message=Cannot write to selected file/location.
label.name=Name:
error.scheme.must.have.a.name=Scheme must have a name
@@ -928,6 +928,11 @@
<smartPointerElementInfoFactory implementation="com.intellij.psi.impl.smartPointers.AnchorElementInfoFactory"/>
<codeInsight.lineMarkerProvider language="" implementationClass="com.intellij.execution.lineMarker.RunLineMarkerProvider"/>
<projectService serviceImplementation="com.intellij.execution.TestStateStorage"/>
<schemeExporter
name="Code Style XML File"
schemeClass="com.intellij.psi.codeStyle.CodeStyleScheme"
implementationClass="com.intellij.psi.impl.source.codeStyle.CodeStyleSchemeCopyExporter"/>
</extensions>
</idea-plugin>
@@ -219,6 +219,11 @@
<with attribute="implementationClass" implements="com.intellij.openapi.options.SchemeImporter"/>
</extensionPoint>
<extensionPoint name="schemeExporter" beanClass="com.intellij.openapi.options.SchemeExporterEP">
<with attribute="schemeClass" implements="com.intellij.openapi.options.Scheme"/>
<with attribute="implementationClass" implements="com.intellij.openapi.options.SchemeExporter"/>
</extensionPoint>
<extensionPoint qualifiedName="org.jetbrains.urlOpener" interface="com.intellij.ide.browsers.UrlOpener"/>
<extensionPoint name="tipAndTrick" beanClass="com.intellij.ide.util.TipAndTrickBean"/>
@@ -2,11 +2,10 @@ package com.intellij.structuralsearch.impl.matcher.handlers;
import com.intellij.psi.PsiElement;
import com.intellij.structuralsearch.impl.matcher.MatchContext;
import com.intellij.structuralsearch.impl.matcher.predicates.RegExpPredicate;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.List;
/**
* Created by IntelliJ IDEA.
@@ -20,30 +19,30 @@ public class LiteralWithSubstitutionHandler extends MatchingHandler {
private Matcher matcher;
private final List<SubstitutionHandler> handlers;
public LiteralWithSubstitutionHandler(String _matchedExpression,List<SubstitutionHandler> _handlers) {
public LiteralWithSubstitutionHandler(String _matchedExpression, List<SubstitutionHandler> _handlers) {
matchExpression = _matchedExpression;
handlers = _handlers;
}
@Override
public boolean match(PsiElement patternNode, PsiElement matchedNode, MatchContext context) {
final String text = RegExpPredicate.getMeaningfulText(matchedNode);
int offset = matchedNode.getText().indexOf(text);
final String text = matchedNode.getText();
if (matcher==null) {
matcher = Pattern.compile(matchExpression).matcher(text);
} else {
matcher.reset(text);
}
while (matcher.find()) {
for (int i = 0; i < handlers.size(); ++i) {
SubstitutionHandler handler = handlers.get(i);
if (!handler.handle(matchedNode,offset + matcher.start(i+1), offset + matcher.end(i+1),context)) {
return false;
}
}
return true;
if (!matcher.find()) {
return false;
}
return false;
for (int i = 0; i < handlers.size(); ++i) {
final SubstitutionHandler handler = handlers.get(i);
if (!handler.handle(matchedNode, matcher.start(i + 1), matcher.end(i + 1), context)) {
return false;
}
}
return true;
}
}
@@ -685,14 +685,42 @@ public class StructuralSearchTest extends StructuralSearchTestCase {
1,
findMatchesCount(s11,s12_3)
);
}
public void testFindArrayDeclarations() {
String source = "class A {" +
" String ss[][];" +
" int f()[] {" +
" return null;" +
" }" +
"}";
String source = "class A { String ss[][]; }";
String target = "String[][] $s$;";
assertEquals(
"should find multi dimensional c-style array declarations",
1,
findMatchesCount(source, target)
);
assertEquals("should find multi-dimensional c-style array declarations", 1, findMatchesCount(source, target));
String target2 = "class '_A { int[] 'f(); }";
assertEquals("should find c-style method return type declarations", 1, findMatchesCount(source, target2));
String target3 = "class '_A { int 'f(); }";
assertEquals("should not find methods with array return types",0, findMatchesCount(source, target3));
String source2 = "class A {" +
" void y(int... i) {}" +
" void y(String... ss) {}" +
" void y(boolean b) {}" +
"}";
assertEquals("find ellipsis type 1", 1, findMatchesCount(source2, "String[] '_a"));
assertEquals("find ellipsis type 2", 1, findMatchesCount(source2, "int[] '_a"));
assertEquals("find ellipsis type 3", 1, findMatchesCount(source2, "class '_X { void '_m(int... '_a); }"));
assertEquals("find ellipsis type 4", 2, findMatchesCount(source2, "'_T[] '_a"));
String source3 = "class A {" +
" private int[] is;" +
"}";
assertEquals("find primitive array 1", 1, findMatchesCount(source3, "int[] '_a;"));
assertEquals("find primitive array 2", 1, findMatchesCount(source3, "'_T[] '_a;"));
assertEquals("find primitive array 3", 1, findMatchesCount(source3, "'_T:[regex( int )][] '_a;"));
assertEquals("find primitive array 4", 1, findMatchesCount(source3, "'_T:[regex( int\\[\\] )] '_a;"));
}
// @todo support back references (\1 in another reg exp or as fild member)
@@ -1,32 +1,22 @@
package com.intellij.testFramework
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VirtualFile
import java.io.File
import java.io.IOException
import java.nio.file.FileVisitResult
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.SimpleFileVisitor
import java.nio.file.attribute.BasicFileAttributes
import java.nio.file.attribute.FileTime
fun Path.exists(): Boolean = Files.exists(this)
fun Path.createDirectories(): Path = Files.createDirectories(this)
fun Path.deleteRecursively(): Path = if (exists()) Files.walkFileTree(this, object : SimpleFileVisitor<Path>() {
override fun visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult {
Files.delete(file)
return FileVisitResult.CONTINUE
}
override fun postVisitDirectory(dir: Path, exc: IOException?): FileVisitResult {
Files.delete(dir)
return FileVisitResult.CONTINUE
}
}) else this
fun Path.deleteRecursively(): Path {
FileUtil.delete(toFile())
return this
}
fun Path.getLastModifiedTime(): FileTime? = Files.getLastModifiedTime(this)
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 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.
@@ -38,7 +38,7 @@ public class HeavyProcessLatch {
}
/**
* @deprecated use {@link #processStarted(java.lang.String)} instead
* @deprecated use {@link #processStarted(String)} instead
*/
@Deprecated
public void processStarted() {
@@ -54,17 +54,22 @@ public class HeavyProcessLatch {
return new AccessToken() {
@Override
public void finish() {
synchronized (myHeavyProcesses) {
myHeavyProcesses.remove(operationName);
}
processFinished(operationName);
}
};
}
@Deprecated // use processStarted(String)
/**
* @deprecated use {@link #processStarted(String)} instead
*/
@Deprecated
public void processFinished() {
processFinished("");
}
private void processFinished(@NotNull String operationName) {
synchronized (myHeavyProcesses) {
myHeavyProcesses.remove("");
myHeavyProcesses.remove(operationName);
}
myEventDispatcher.getMulticaster().processFinished();
}
@@ -83,9 +88,8 @@ public class HeavyProcessLatch {
public interface HeavyProcessListener extends EventListener {
public void processStarted();
public void processFinished();
void processStarted();
void processFinished();
}
public void addListener(@NotNull Disposable parentDisposable, @NotNull HeavyProcessListener listener) {
@@ -3077,13 +3077,25 @@ public class UIUtil {
// Evaluate the value depending on our current theme
if (lcdContrastValue == 0) {
lcdContrastValue = UIUtil.isUnderDarcula() ? 100 : 250;
if (SystemInfo.isMacIntel64) {
lcdContrastValue = UIUtil.isUnderDarcula() ? 100 : 250;
} else {
Map map = (Map)Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints");
if (map == null) {
lcdContrastValue = 140;
} else {
Object o = map.get(RenderingHints.KEY_TEXT_LCD_CONTRAST);
lcdContrastValue = (o == null) ? 140 : ((Integer)o);
}
}
}
if (lcdContrastValue < 100 || lcdContrastValue > 250) {
// the default value
lcdContrastValue = 140;
}
return lcdContrastValue;
}
@@ -181,7 +181,8 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
invokeAfterUpdate(new Runnable() {
@Override
public void run() {
if (getChangeList(oldList.getId()) == null) {
LocalChangeList actualList = getChangeList(oldList.getId());
if (actualList == null) {
return; // removed already
}
@@ -189,7 +190,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
config.REMOVE_EMPTY_INACTIVE_CHANGELISTS != VcsShowConfirmationOption.Value.DO_ACTION_SILENTLY) {
myListsToBeDeleted.add(oldList);
} else {
deleteEmptyChangeLists(Collections.singletonList(oldList));
deleteEmptyChangeLists(Collections.singletonList(actualList));
}
}
}, InvokeAfterUpdateMode.SILENT, null, null);
@@ -20,7 +20,6 @@ import com.intellij.openapi.vcs.ProjectLevelVcsManager
import com.intellij.openapi.vcs.changes.ChangeListManager
import com.intellij.openapi.vcs.changes.LocalChangeList
import com.intellij.util.ThreeState
import com.intellij.util.containers.ContainerUtil
abstract class ChangeListRemoveConfirmation() {
@@ -29,32 +28,35 @@ abstract class ChangeListRemoveConfirmation() {
companion object {
@JvmStatic
fun processLists(project: Project, explicitly: Boolean, allLists: Collection<LocalChangeList>, ask: ChangeListRemoveConfirmation) {
val confirmationAsked = ContainerUtil.newIdentityTroveSet<LocalChangeList>()
val doNotRemove = ContainerUtil.newIdentityTroveSet<LocalChangeList>()
val allIds = allLists.map { it.id }
val confirmationAsked = hashSetOf<String>()
val doNotRemove = hashSetOf<String>()
for (list in allLists) {
val manager = ChangeListManager.getInstance(project)
for (id in allIds) {
for (vcs in ProjectLevelVcsManager.getInstance(project).getAllActiveVcss()) {
val permission = vcs.mayRemoveChangeList(list, explicitly)
val list = manager.getChangeList(id)
val permission = if (list == null) ThreeState.NO else vcs.mayRemoveChangeList(list, explicitly)
if (permission != ThreeState.UNSURE) {
confirmationAsked.add(list)
confirmationAsked.add(id)
}
if (permission == ThreeState.NO) {
doNotRemove.add(list)
doNotRemove.add(id)
break
}
}
}
val toAsk = allLists.filter { it !in confirmationAsked && it !in doNotRemove }
if (toAsk.isNotEmpty() && !ask.askIfShouldRemoveChangeLists(toAsk)) {
val toAsk = allIds.filter { it !in confirmationAsked && it !in doNotRemove }
if (toAsk.isNotEmpty() && !ask.askIfShouldRemoveChangeLists(toAsk.map { manager.getChangeList(it) }.filterNotNull())) {
doNotRemove.addAll(toAsk)
}
val toRemove = allLists.filter { it !in doNotRemove }
val active = toRemove.find { it.isDefault() }
toRemove.forEach { if (it != active) ChangeListManager.getInstance(project).removeChangeList(it.getName()) }
val toRemove = allIds.filter { it !in doNotRemove }.map { manager.getChangeList(it) }.filterNotNull()
val active = toRemove.find { it.isDefault }
toRemove.forEach { if (it != active) manager.removeChangeList(it.name) }
if (active != null && RemoveChangeListAction.confirmActiveChangeListRemoval(project, listOf(active), active.getChanges().isEmpty())) {
ChangeListManager.getInstance(project).removeChangeList(active.getName())
manager.removeChangeList(active.name)
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2015 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.
@@ -17,6 +17,7 @@ package com.intellij.openapi.vcs.configurable;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
@@ -48,6 +49,7 @@ public abstract class VcsCheckBoxWithSpinnerConfigurable implements Configurable
}
@Override
@NotNull
public JComponent createComponent() {
JPanel wrapper = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
myHighlightRecentlyChanged = new JCheckBox(myCheckboxText);
@@ -142,8 +142,8 @@ public class TryFinallyCanBeTryWithResourcesInspection extends BaseInspection {
}
separator = true;
}
int j = 1;
if (!unwantedChildren.isEmpty()) {
int j = 1;
while (!unwantedChildren.contains(Integer.valueOf(j)) && j < tryBlockChildren.length - 1) {
tryStatement.getParent().addBefore(tryBlockChildren[j], tryStatement);
unwantedChildren.add(j);
@@ -329,7 +329,7 @@ public class TryFinallyCanBeTryWithResourcesInspection extends BaseInspection {
hasInitializer = !PsiType.NULL.equals(type);
}
final int index = findInitialization(tryBlockStatements, variable, hasInitializer);
if (!(index >= 0 ^ hasInitializer) || isVariableUsedOutsideContext(variable, tryBlock)) {
if ((index >= 0) == hasInitializer || isVariableUsedOutsideContext(variable, tryBlock)) {
return;
}
}
@@ -50,14 +50,14 @@ public class PyContentEntriesEditor extends CommonContentEntriesEditor {
private final Module myModule;
private Disposable myFilePointersDisposable;
private MyContentEntryEditor myContentEntryEditor;
private FacetErrorPanel myErrorPanel;
private FacetErrorPanel myWarningPanel;
public PyContentEntriesEditor(Module module, ModuleConfigurationState moduleConfigurationState,
JpsModuleSourceRootType<?>... rootTypes) {
super(module.getName(), moduleConfigurationState, rootTypes);
myRootTypeProviders = Extensions.getExtensions(PyRootTypeProvider.EP_NAME);
myModule = module;
myErrorPanel = new FacetErrorPanel();
myWarningPanel = new FacetErrorPanel();
reset();
}
@@ -105,6 +105,10 @@ public class PyContentEntriesEditor extends CommonContentEntriesEditor {
if (myFilePointersDisposable != null) {
Disposer.dispose(myFilePointersDisposable);
}
for (PyRootTypeProvider provider : myRootTypeProviders) {
provider.disposeUIResources(myModule);
}
}
@Override
@@ -292,10 +296,10 @@ public class PyContentEntriesEditor extends CommonContentEntriesEditor {
@Override
protected void addAdditionalSettingsToPanel(JPanel mainPanel) {
mainPanel.add(myErrorPanel.getComponent(), BorderLayout.SOUTH);
mainPanel.add(myWarningPanel.getComponent(), BorderLayout.SOUTH);
}
public FacetErrorPanel getErrorPanel() {
return myErrorPanel;
public FacetErrorPanel getWarningPanel() {
return myWarningPanel;
}
}
@@ -48,7 +48,7 @@ public abstract class PyRootTypeProvider {
}
};
public abstract void reset(@NotNull final Disposable disposable, PyContentEntriesEditor editor, Module module);
public abstract void reset(@NotNull final Disposable disposable, PyContentEntriesEditor editor, @NotNull Module module);
public abstract void apply(Module module);
@@ -76,6 +76,9 @@ public abstract class PyRootTypeProvider {
return null;
}
public void disposeUIResources(@NotNull Module module) {
}
protected class RootEntryEditingAction extends ContentEntryEditingAction {
private final Disposable myDisposable;
@@ -123,12 +126,12 @@ public abstract class PyRootTypeProvider {
private void addRoot(VirtualFilePointer root, PyContentEntriesEditor editor) {
editor.getContentEntryEditor().addRoot(this, root);
editor.getErrorPanel().getValidatorsManager().validate();
editor.getWarningPanel().getValidatorsManager().validate();
}
protected void removeRoot(VirtualFile selectedFile, PyContentEntriesEditor editor, ModifiableRootModel model) {
editor.getContentEntryEditor().removeRoot(null, selectedFile.getUrl(), this);
editor.getErrorPanel().getValidatorsManager().validate();
editor.getWarningPanel().getValidatorsManager().validate();
}
protected boolean hasRoot(VirtualFile file, PyContentEntriesEditor editor) {
@@ -49,7 +49,7 @@ import static com.intellij.codeInsight.completion.CompletionUtilCore.DUMMY_IDENT
/**
* @author Mike
*/
public class XmlAttributeImpl extends XmlElementImpl implements XmlAttribute {
public class XmlAttributeImpl extends XmlElementImpl implements XmlAttribute, HintedReferenceHost {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.xml.XmlAttributeImpl");
private final int myHC = ourHC++;
@@ -330,14 +330,36 @@ public class XmlAttributeImpl extends XmlElementImpl implements XmlAttribute {
@Override
public PsiReference getReference() {
final PsiReference[] refs = getReferences();
final PsiReference[] refs = getReferences(PsiReferenceService.Hints.NO_HINTS);
if (refs.length > 0) return refs[0];
return null;
}
@Override
public boolean shouldAskParentForReferences(@NotNull PsiReferenceService.Hints hints) {
return false;
}
/**
* Use {@link #getReferences(PsiReferenceService.Hints)} instead of calling or overriding this method.
*/
@Deprecated
@NotNull
public PsiReference[] getReferences() {
@Override
public final PsiReference[] getReferences() {
return getReferences(PsiReferenceService.Hints.NO_HINTS);
}
@NotNull
@Override
public PsiReference[] getReferences(@NotNull PsiReferenceService.Hints hints) {
if (hints.offsetInElement != null) {
XmlElement nameElement = getNameElement();
if (nameElement == null || hints.offsetInElement > nameElement.getStartOffsetInParent() + nameElement.getTextLength()) {
return PsiReference.EMPTY_ARRAY;
}
}
final PsiReference[] referencesFromProviders = ReferenceProvidersRegistry.getReferencesFromProviders(this);
PsiReference[] refs;
if (isNamespaceDeclaration()) {
@@ -74,7 +74,7 @@ import java.util.*;
* @author Mike
*/
public class XmlTagImpl extends XmlElementImpl implements XmlTag {
public class XmlTagImpl extends XmlElementImpl implements XmlTag, HintedReferenceHost {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.xml.XmlTagImpl");
@NonNls private static final String XML_NS_PREFIX = "xml";
private static final RecursionGuard ourGuard = RecursionManager.createGuard("xmlTag");
@@ -93,10 +93,17 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag {
.create(tags, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT, tag.getContainingFile());
}
};
private static final Comparator<TextRange> RANGE_COMPARATOR = new Comparator<TextRange>() {
@Override
public int compare(TextRange range1, TextRange range2) {
return range1.getStartOffset() - range2.getStartOffset();
}
};
private final int myHC = ourHC++;
private volatile String myName = null;
private volatile String myLocalName;
private volatile XmlAttribute[] myAttributes = null;
private volatile TextRange[] myTextElements = null;
private volatile Map<String, String> myAttributeValueMap = null;
private volatile XmlTagValue myValue = null;
private volatile Map<String, CachedValue<XmlNSDescriptor>> myNSDescriptorsMap = null;
@@ -152,6 +159,7 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag {
myCachedDescriptor = null;
myDescriptorModCount = -1;
myAttributes = null;
myTextElements = null;
myAttributeValueMap = null;
myHasNamespaceDeclarations = false;
myValue = null;
@@ -159,9 +167,24 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag {
super.clearCaches();
}
@Override
/**
* Use {@link #getReferences(PsiReferenceService.Hints)} instead of calling or overriding this method.
*/
@Deprecated
@NotNull
public PsiReference[] getReferences() {
@Override
public final PsiReference[] getReferences() {
return getReferences(PsiReferenceService.Hints.NO_HINTS);
}
@Override
public boolean shouldAskParentForReferences(@NotNull PsiReferenceService.Hints hints) {
return false;
}
@NotNull
@Override
public PsiReference[] getReferences(@NotNull PsiReferenceService.Hints hints) {
ProgressManager.checkCanceled();
final ASTNode startTagName = XmlChildRole.START_TAG_NAME_FINDER.findChild(this);
if (startTagName == null) return PsiReference.EMPTY_ARRAY;
@@ -169,14 +192,18 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag {
List<PsiReference> refs = new ArrayList<PsiReference>();
String prefix = getNamespacePrefix();
TagNameReference startTagRef = TagNameReference.createTagNameReference(this, startTagName, true);
if (startTagRef != null) {
refs.add(startTagRef);
boolean inStartTag = hints.offsetInElement == null || childContainsOffset(startTagName.getPsi(), hints.offsetInElement);
if (inStartTag) {
TagNameReference startTagRef = TagNameReference.createTagNameReference(this, startTagName, true);
if (startTagRef != null) {
refs.add(startTagRef);
}
if (!prefix.isEmpty()) {
refs.add(createPrefixReference(startTagName, prefix, startTagRef));
}
}
if (!prefix.isEmpty()) {
refs.add(createPrefixReference(startTagName, prefix, startTagRef));
}
if (endTagName != null) {
boolean inEndTag = endTagName != null && (hints.offsetInElement == null || childContainsOffset(endTagName.getPsi(), hints.offsetInElement));
if (inEndTag) {
TagNameReference endTagRef = TagNameReference.createTagNameReference(this, endTagName, false);
if (endTagRef != null) {
refs.add(endTagRef);
@@ -187,16 +214,43 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag {
}
}
// ArrayList.addAll() makes a clone of the collection
//noinspection ManualArrayToCollectionCopy
for (PsiReference ref : ReferenceProvidersRegistry.getReferencesFromProviders(this, XmlTag.class)) {
refs.add(ref);
if (hints.offsetInElement == null || inStartTag || inEndTag || isInsideXmlText(hints.offsetInElement)) {
Collections.addAll(refs, ReferenceProvidersRegistry.getReferencesFromProviders(this, hints));
}
return ContainerUtil.toArray(refs, new PsiReference[refs.size()]);
}
private static boolean childContainsOffset(PsiElement child, int offsetInTag) {
return child.getStartOffsetInParent() <= offsetInTag && offsetInTag <= child.getStartOffsetInParent() + child.getTextLength();
}
private boolean isInsideXmlText(int offsetInTag) {
TextRange[] ranges = getValueTextRanges();
if (ranges.length == 0) return false;
if (offsetInTag < ranges[0].getStartOffset() || offsetInTag > ranges[ranges.length - 1].getEndOffset()) return false;
int i = Arrays.binarySearch(ranges, TextRange.from(offsetInTag, 0), RANGE_COMPARATOR);
return i >= 0 || ranges[-i - 2].containsOffset(offsetInTag);
}
@NotNull
private TextRange[] getValueTextRanges() {
TextRange[] elements = myTextElements;
if (elements == null) {
List<TextRange> list = ContainerUtil.newSmartList();
// don't use getValue().getXmlElements() because it processes includes & entities, and we only need textual AST here
for (ASTNode child = getFirstChildNode(); child != null; child = child.getTreeNext()) {
PsiElement psi = child.getPsi();
if (psi instanceof XmlText) {
list.add(TextRange.from(psi.getStartOffsetInParent(), psi.getTextLength()));
}
}
myTextElements = elements = list.toArray(new TextRange[list.size()]);
}
return elements;
}
private SchemaPrefixReference createPrefixReference(ASTNode startTagName, String prefix, TagNameReference tagRef) {
return new SchemaPrefixReference(this, TextRange.from(startTagName.getStartOffset() - getStartOffset(), prefix.length()), prefix,
tagRef);
@@ -428,7 +482,7 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag {
@Override
public PsiReference getReference() {
return ArrayUtil.getFirstElement(getReferences());
return ArrayUtil.getFirstElement(getReferences(PsiReferenceService.Hints.NO_HINTS));
}
@Override