mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
+2
-3
@@ -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
|
||||
|
||||
+7
-11
@@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
+113
-22
@@ -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;
|
||||
}
|
||||
|
||||
+15
-1
@@ -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) {
|
||||
|
||||
+16
-6
@@ -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
|
||||
|
||||
+14
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -160,6 +160,6 @@ public class StrictSubtypingConstraint implements ConstraintFormula {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return myS.getPresentableText() + " < " + myT.getPresentableText();
|
||||
return myT.getPresentableText() + " < " + myS.getPresentableText();
|
||||
}
|
||||
}
|
||||
|
||||
+14
-10
@@ -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;
|
||||
}
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
@interface Foo {
|
||||
boolean foo();
|
||||
}
|
||||
|
||||
@Foo(foo=<caret>)
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
@interface Foo {
|
||||
MyEnum value();
|
||||
}
|
||||
enum MyEnum { x, y }
|
||||
|
||||
@Foo(<caret>)
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
@interface Foo {
|
||||
int value();
|
||||
}
|
||||
|
||||
@Foo(<caret>)
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
@interface Foo {
|
||||
Class attr();
|
||||
}
|
||||
|
||||
@Foo(attr = <caret>)
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
@interface Foo {
|
||||
Class value();
|
||||
}
|
||||
|
||||
@Foo(<caret>)
|
||||
+21
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+7
-1
@@ -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"); }
|
||||
|
||||
+23
-1
@@ -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()
|
||||
|
||||
|
||||
+4
@@ -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" +
|
||||
|
||||
+89
-104
@@ -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();
|
||||
|
||||
+5
-5
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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, '\\');
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
+2
-1
@@ -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) {
|
||||
|
||||
+119
@@ -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);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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&xport..."/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="816ef" class="javax.swing.JButton" binding="myImportButton" default-binding="true">
|
||||
|
||||
+22
-4
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
+18
-3
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-6
@@ -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);
|
||||
}
|
||||
|
||||
+82
@@ -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
|
||||
|
||||
+3
@@ -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() {
|
||||
|
||||
+88
@@ -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();
|
||||
}
|
||||
}
|
||||
+8
-56
@@ -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();
|
||||
|
||||
+33
-47
@@ -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);
|
||||
|
||||
+166
-276
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+205
@@ -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;
|
||||
|
||||
+31
-26
@@ -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");
|
||||
}
|
||||
|
||||
+8
-6
@@ -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
|
||||
|
||||
+5
-5
@@ -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"/>
|
||||
|
||||
|
||||
+14
-15
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+34
-6
@@ -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);
|
||||
|
||||
+15
-13
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -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);
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user