Merge branch 'master' into changeSignature

Conflicts:
	plugins/groovy/testdata/highlighting/MethodDuplicates.groovy
This commit is contained in:
Maxim Medvedev
2010-04-23 11:05:23 +04:00
97 changed files with 2008 additions and 1037 deletions
@@ -51,7 +51,7 @@ public class JavaCompletionStatistician extends CompletionStatistician{
}
}
LookupItem item = element.as(LookupItem.class);
LookupItem item = LookupItem.from(element);
if (item == null) return null;
PsiType qualifierType = JavaCompletionUtil.getQualifierType(item);
@@ -789,9 +789,8 @@ public class JavaCompletionUtil {
return typed.getType();
}
final PsiType qualifierType = getPsiType(element.getObject());
final LookupItem lookupItem = element.as(LookupItem.class);
final LookupItem lookupItem = LookupItem.from(element);
if (lookupItem != null) {
final Object o = lookupItem.getAttribute(LookupItem.TYPE);
if (o instanceof PsiType) {
@@ -31,6 +31,10 @@ public class StaticMembersWeigher extends CompletionWeigher {
final PsiElement position = loc.getCompletionParameters().getPosition();
if (!position.isValid()) return 0;
// cheap weigher applicability goes first
final Object o = element.getObject();
if (!(o instanceof PsiMember)) return 0;
if (PsiTreeUtil.getParentOfType(position, PsiDocComment.class) != null) return 0;
if (position.getParent() instanceof PsiReferenceExpression) {
final PsiReferenceExpression refExpr = (PsiReferenceExpression)position.getParent();
@@ -43,9 +47,6 @@ public class StaticMembersWeigher extends CompletionWeigher {
}
}
final Object o = element.getObject();
if (!(o instanceof PsiMember)) return 0;
if (((PsiMember)o).hasModifierProperty(PsiModifier.STATIC)) {
if (o instanceof PsiMethod) return 5;
if (o instanceof PsiField) return 4;
@@ -16,14 +16,11 @@
package com.intellij.openapi.options.colors.pages;
import com.intellij.application.options.colors.InspectionColorSettingsPage;
import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
import com.intellij.codeInsight.daemon.impl.SeveritiesProvider;
import com.intellij.ide.highlighter.JavaFileHighlighter;
import com.intellij.openapi.editor.HighlighterColors;
import com.intellij.openapi.editor.SyntaxHighlighterColors;
import com.intellij.openapi.editor.colors.CodeInsightColors;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.fileTypes.SyntaxHighlighter;
import com.intellij.openapi.options.OptionsBundle;
@@ -136,12 +133,6 @@ public class JavaColorSettingsPage implements ColorSettingsPage, InspectionColor
descriptors.add(new AttributesDescriptor(OptionsBundle.message("options.java.color.descriptor.full.coverage"), CodeInsightColors.LINE_FULL_COVERAGE));
descriptors.add(new AttributesDescriptor(OptionsBundle.message("options.java.color.descriptor.partial.coverage"), CodeInsightColors.LINE_PARTIAL_COVERAGE));
descriptors.add(new AttributesDescriptor(OptionsBundle.message("options.java.color.descriptor.none.coverage"), CodeInsightColors.LINE_NONE_COVERAGE));
for (SeveritiesProvider provider : Extensions.getExtensions(SeveritiesProvider.EP_NAME)) {
for (HighlightInfoType highlightInfoType : provider.getSeveritiesHighlightInfoTypes()) {
final TextAttributesKey attributesKey = highlightInfoType.getAttributesKey();
descriptors.add(new AttributesDescriptor(attributesKey.myExternalName, attributesKey));
}
}
return descriptors.toArray(new AttributesDescriptor[descriptors.size()]);
}
@@ -24,6 +24,8 @@ import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.formatter.FormatterUtil;
import com.intellij.psi.formatter.common.AbstractBlock;
import com.intellij.psi.formatter.common.JavaBlockUtil;
import com.intellij.psi.formatter.java.wrap.JavaWrapManager;
import com.intellij.psi.formatter.java.wrap.ReservedWrapsProvider;
import com.intellij.psi.impl.source.SourceTreeToPsiMap;
import com.intellij.psi.impl.source.tree.*;
import com.intellij.psi.impl.source.tree.java.ClassElement;
@@ -37,7 +39,7 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlock {
public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlock, ReservedWrapsProvider {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.formatter.java.AbstractJavaBlock");
protected final CodeStyleSettings mySettings;
@@ -51,16 +53,21 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
protected Alignment myReservedAlignment;
protected Alignment myReservedAlignment2;
private final JavaWrapManager myWrapManager;
protected AbstractJavaBlock(final ASTNode node,
final Wrap wrap,
final Alignment alignment,
final Indent indent,
final CodeStyleSettings settings) {
protected AbstractJavaBlock(final ASTNode node, final Wrap wrap, final Alignment alignment, final Indent indent,
final CodeStyleSettings settings)
{
this(node, wrap, alignment, indent, settings, JavaWrapManager.INSTANCE);
}
protected AbstractJavaBlock(final ASTNode node, final Wrap wrap, final Alignment alignment, final Indent indent,
final CodeStyleSettings settings, JavaWrapManager wrapManager)
{
super(node, wrap, alignment);
mySettings = settings;
myIndent = indent;
myWrapManager = wrapManager;
}
public static Block createJavaBlock(final ASTNode child,
@@ -159,7 +166,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
}
}
final ASTNode prevElement = getPrevElement(child);
final ASTNode prevElement = FormattingAstUtil.getPrevElement(child);
if (prevElement != null && prevElement.getElementType() == JavaElementType.MODIFIER_LIST) {
return Indent.getNoneIndent();
}
@@ -234,51 +241,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
@Nullable
protected Wrap createChildWrap() {
final IElementType nodeType = myNode.getElementType();
if (nodeType == JavaElementType.EXTENDS_LIST || nodeType == JavaElementType.IMPLEMENTS_LIST) {
return Wrap.createWrap(getWrapType(mySettings.EXTENDS_LIST_WRAP), false);
}
else if (nodeType == JavaElementType.BINARY_EXPRESSION) {
Wrap actualWrap = myWrap != null ? myWrap : getReservedWrap(JavaElementType.BINARY_EXPRESSION);
if (actualWrap == null) {
return Wrap.createWrap(getWrapType(mySettings.BINARY_OPERATION_WRAP), false);
}
else {
if (!hasTheSamePriority(myNode.getTreeParent())) {
return Wrap.createChildWrap(actualWrap, getWrapType(mySettings.BINARY_OPERATION_WRAP), false);
}
else {
return actualWrap;
}
}
}
else if (nodeType == JavaElementType.CONDITIONAL_EXPRESSION) {
return Wrap.createWrap(getWrapType(mySettings.TERNARY_OPERATION_WRAP), false);
}
else if (nodeType == JavaElementType.ASSERT_STATEMENT) {
return Wrap.createWrap(getWrapType(mySettings.ASSERT_STATEMENT_WRAP), false);
}
else if (nodeType == JavaElementType.FOR_STATEMENT) {
return Wrap.createWrap(getWrapType(mySettings.FOR_STATEMENT_WRAP), false);
}
else if (nodeType == JavaElementType.THROWS_LIST) {
return Wrap.createWrap(getWrapType(mySettings.THROWS_LIST_WRAP), true);
}
else if (nodeType == JavaElementType.CODE_BLOCK) {
return Wrap.createWrap(Wrap.NORMAL, false);
}
else if (isAssignment()) {
return Wrap.createWrap(getWrapType(mySettings.ASSIGNMENT_WRAP), true);
}
else {
return null;
}
}
private boolean isAssignment() {
final IElementType nodeType = myNode.getElementType();
return nodeType == JavaElementType.ASSIGNMENT_EXPRESSION || nodeType == JavaElementType.LOCAL_VARIABLE
|| nodeType == JavaElementType.FIELD;
return myWrapManager.createChildBlockWrap(this, getSettings(), this);
}
@Nullable
@@ -375,14 +338,14 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
if (myNode.getElementType() == JavaElementType.BINARY_EXPRESSION) {
final ASTNode treeParent = myNode.getTreeParent();
if (treeParent != null && treeParent.getElementType() == JavaElementType.BINARY_EXPRESSION) {
return hasTheSamePriority(treeParent);
return FormattingAstUtil.binaryExpressionHasTheSamePriority(myNode, treeParent);
}
}
return false;
}
@Nullable
protected ASTNode processChild(final ArrayList<Block> result,
protected ASTNode processChild(final List<Block> result,
ASTNode child,
Alignment defaultAlignment,
final Wrap defaultWrap,
@@ -391,7 +354,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
}
@Nullable
protected ASTNode processChild(final ArrayList<Block> result,
protected ASTNode processChild(final List<Block> result,
ASTNode child,
Alignment defaultAlignment,
final Wrap defaultWrap,
@@ -411,7 +374,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
if (childType == JavaTokenType.LBRACE && nodeType == JavaElementType.ARRAY_INITIALIZER_EXPRESSION) {
final Wrap wrap = Wrap.createWrap(getWrapType(mySettings.ARRAY_INITIALIZER_WRAP), false);
child = processParenBlock(JavaTokenType.LBRACE, JavaTokenType.RBRACE,
child = processParenthesisBlock(JavaTokenType.LBRACE, JavaTokenType.RBRACE,
result,
child,
WrappingStrategy.createDoNotWrapCommaStrategy(wrap),
@@ -419,7 +382,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
}
else if (childType == JavaTokenType.LBRACE && nodeType == JavaElementType.ANNOTATION_ARRAY_INITIALIZER) {
final Wrap wrap = Wrap.createWrap(getWrapType(mySettings.ARRAY_INITIALIZER_WRAP), false);
child = processParenBlock(JavaTokenType.LBRACE, JavaTokenType.RBRACE,
child = processParenthesisBlock(JavaTokenType.LBRACE, JavaTokenType.RBRACE,
result,
child,
WrappingStrategy.createDoNotWrapCommaStrategy(wrap),
@@ -430,7 +393,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
if (mySettings.PREFER_PARAMETERS_WRAP) {
wrap.ignoreParentWraps();
}
child = processParenBlock(result,
child = processParenthesisBlock(result,
child,
WrappingStrategy.createDoNotWrapCommaStrategy(wrap),
mySettings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS);
@@ -438,18 +401,18 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
else if (childType == JavaTokenType.LPARENTH && nodeType == JavaElementType.PARAMETER_LIST) {
final Wrap wrap = Wrap.createWrap(getWrapType(mySettings.METHOD_PARAMETERS_WRAP), false);
child = processParenBlock(result, child,
child = processParenthesisBlock(result, child,
WrappingStrategy.createDoNotWrapCommaStrategy(wrap),
mySettings.ALIGN_MULTILINE_PARAMETERS);
}
else if (childType == JavaTokenType.LPARENTH && nodeType == JavaElementType.ANNOTATION_PARAMETER_LIST) {
final Wrap wrap = Wrap.createWrap(getWrapType(mySettings.CALL_PARAMETERS_WRAP), false);
child = processParenBlock(result, child,
child = processParenthesisBlock(result, child,
WrappingStrategy.createDoNotWrapCommaStrategy(wrap),
mySettings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS);
}
else if (childType == JavaTokenType.LPARENTH && nodeType == JavaElementType.PARENTH_EXPRESSION) {
child = processParenBlock(result, child,
child = processParenthesisBlock(result, child,
WrappingStrategy.DO_NOT_WRAP,
mySettings.ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION);
}
@@ -501,7 +464,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
return child;
}
private ASTNode processField(final ArrayList<Block> result, ASTNode child, final Alignment defaultAlignment, final Wrap defaultWrap,
private ASTNode processField(final List<Block> result, ASTNode child, final Alignment defaultAlignment, final Wrap defaultWrap,
final Indent childIndent) {
ASTNode lastFieldInGroup = findLastFieldInGroup(child);
if (lastFieldInGroup == child) {
@@ -563,7 +526,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
}
@Nullable
private ASTNode processTernaryOperationRange(final ArrayList<Block> result,
private ASTNode processTernaryOperationRange(final List<Block> result,
final ASTNode child, final Wrap defaultWrap, final Indent childIndent) {
final ArrayList<Block> localResult = new ArrayList<Block>();
final Wrap wrap = arrangeChildWrap(child, defaultWrap);
@@ -825,186 +788,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
myAnnotationWrap = null;
}
}
final ASTNode parent = child.getTreeParent();
int role = ((CompositeElement)parent).getChildRole(child);
final IElementType nodeType = myNode.getElementType();
if (nodeType == JavaElementType.BINARY_EXPRESSION) {
if (role == ChildRole.OPERATION_SIGN && !mySettings.BINARY_OPERATION_SIGN_ON_NEXT_LINE) return null;
if (role == ChildRole.ROPERAND && mySettings.BINARY_OPERATION_SIGN_ON_NEXT_LINE) return null;
return defaultWrap;
}
final IElementType childType = child.getElementType();
if (childType == JavaElementType.EXTENDS_LIST || childType == JavaElementType.IMPLEMENTS_LIST) {
return Wrap.createWrap(getWrapType(mySettings.EXTENDS_KEYWORD_WRAP), true);
}
else if (childType == JavaElementType.THROWS_LIST) {
return Wrap.createWrap(getWrapType(mySettings.THROWS_KEYWORD_WRAP), true);
}
else if (nodeType == JavaElementType.EXTENDS_LIST || nodeType == JavaElementType.IMPLEMENTS_LIST) {
if (role == ChildRole.REFERENCE_IN_LIST) {
return defaultWrap;
}
else {
return null;
}
}
else if (nodeType == JavaElementType.THROWS_LIST) {
if (role == ChildRole.REFERENCE_IN_LIST) {
return defaultWrap;
}
else {
return null;
}
}
else if (nodeType == JavaElementType.CONDITIONAL_EXPRESSION) {
if (role == ChildRole.COLON && !mySettings.TERNARY_OPERATION_SIGNS_ON_NEXT_LINE) return null;
if (role == ChildRole.QUEST && !mySettings.TERNARY_OPERATION_SIGNS_ON_NEXT_LINE) return null;
if (role == ChildRole.THEN_EXPRESSION && mySettings.TERNARY_OPERATION_SIGNS_ON_NEXT_LINE) return null;
if (role == ChildRole.ELSE_EXPRESSION && mySettings.TERNARY_OPERATION_SIGNS_ON_NEXT_LINE) return null;
return defaultWrap;
}
else if (isAssignment()) {
if (role == ChildRole.INITIALIZER_EQ && mySettings.PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE) return defaultWrap;
if (role == ChildRole.INITIALIZER_EQ && !mySettings.PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE) return null;
if (role == ChildRole.OPERATION_SIGN && mySettings.PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE) return defaultWrap;
if (role == ChildRole.OPERATION_SIGN && !mySettings.PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE) return null;
if (role == ChildRole.INITIALIZER && !mySettings.PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE) return defaultWrap;
if (role == ChildRole.INITIALIZER && mySettings.PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE) return null;
if (role == ChildRole.ROPERAND && !mySettings.PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE) return defaultWrap;
if (role == ChildRole.ROPERAND && mySettings.PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE) return null;
if (role == ChildRole.CLOSING_SEMICOLON) return null;
//if (role == ChildRole.TYPE) return defaultWrap;
return defaultWrap;
}
else if (nodeType == JavaElementType.REFERENCE_EXPRESSION) {
if (role == ChildRole.DOT) {
return getReservedWrap(JavaElementType.REFERENCE_EXPRESSION);
}
else {
return defaultWrap;
}
}
else if (nodeType == JavaElementType.FOR_STATEMENT) {
if (role == ChildRole.FOR_INITIALIZATION || role == ChildRole.CONDITION || role == ChildRole.FOR_UPDATE) {
return defaultWrap;
}
if (role == ChildRole.LOOP_BODY) {
final boolean dontWrap = (childType == JavaElementType.CODE_BLOCK || childType == JavaElementType.BLOCK_STATEMENT) &&
mySettings.BRACE_STYLE == CodeStyleSettings.END_OF_LINE;
return Wrap.createWrap(dontWrap ? WrapType.NONE : WrapType.NORMAL, true);
}
else {
return null;
}
}
else if (nodeType == JavaElementType.METHOD) {
if (role == ChildRole.THROWS_LIST) {
return defaultWrap;
}
else {
return null;
}
}
else if (nodeType == JavaElementType.MODIFIER_LIST) {
if (childType == JavaElementType.ANNOTATION) {
return getReservedWrap(JavaElementType.MODIFIER_LIST);
}
ASTNode prevElement = getPrevElement(child);
if (prevElement != null && prevElement.getElementType() == JavaElementType.ANNOTATION) {
return getReservedWrap(JavaElementType.MODIFIER_LIST);
}
else {
return null;
}
}
else if (nodeType == JavaElementType.ASSERT_STATEMENT) {
if (role == ChildRole.CONDITION) {
return defaultWrap;
}
if (role == ChildRole.ASSERT_DESCRIPTION && !mySettings.ASSERT_STATEMENT_COLON_ON_NEXT_LINE) {
return defaultWrap;
}
if (role == ChildRole.COLON && mySettings.ASSERT_STATEMENT_COLON_ON_NEXT_LINE) {
return defaultWrap;
}
return null;
}
else if (nodeType == JavaElementType.CODE_BLOCK) {
if (role == ChildRole.STATEMENT_IN_BLOCK) {
return defaultWrap;
}
else {
return null;
}
}
else if (nodeType == JavaElementType.IF_STATEMENT) {
if (childType == JavaElementType.IF_STATEMENT && role == ChildRole.ELSE_BRANCH && getSettings().SPECIAL_ELSE_IF_TREATMENT) {
return Wrap.createWrap(WrapType.NONE, false);
}
if (role == ChildRole.THEN_BRANCH || role == ChildRole.ELSE_BRANCH) {
if (childType == JavaElementType.BLOCK_STATEMENT) {
return null;
}
else {
return Wrap.createWrap(WrapType.NORMAL, true);
}
}
}
else if (nodeType == JavaElementType.FOREACH_STATEMENT || nodeType == JavaElementType.WHILE_STATEMENT) {
if (role == ChildRole.LOOP_BODY) {
if (childType == JavaElementType.BLOCK_STATEMENT) {
return null;
}
else {
return Wrap.createWrap(WrapType.NORMAL, true);
}
}
}
else if (nodeType == JavaElementType.DO_WHILE_STATEMENT) {
if (role == ChildRole.LOOP_BODY) {
return Wrap.createWrap(WrapType.NORMAL, true);
} else if (role == ChildRole.WHILE_KEYWORD) {
return Wrap.createWrap(WrapType.NORMAL, true);
}
} else if (nodeType == JavaElementType.ANNOTATION_ARRAY_INITIALIZER) {
if (role == ChildRole.ANNOTATION_VALUE) {
return Wrap.createWrap(WrapType.NORMAL, true);
}
}
return defaultWrap;
}
@Nullable
private static ASTNode getPrevElement(final ASTNode child) {
ASTNode result = child.getTreePrev();
while (result != null && result.getElementType() == TokenType.WHITE_SPACE) {
result = result.getTreePrev();
}
return result;
}
private boolean hasTheSamePriority(final ASTNode node) {
if (node == null) return false;
if (node.getElementType() != JavaElementType.BINARY_EXPRESSION) {
return false;
}
else {
final PsiBinaryExpression expr1 = (PsiBinaryExpression)SourceTreeToPsiMap.treeElementToPsi(myNode);
final PsiBinaryExpression expr2 = (PsiBinaryExpression)SourceTreeToPsiMap.treeElementToPsi(node);
final PsiJavaToken op1 = expr1.getOperationSign();
final PsiJavaToken op2 = expr2.getOperationSign();
return op1.getTokenType() == op2.getTokenType();
}
return myWrapManager.arrangeChildWrap(child, myNode, getSettings(), defaultWrap, this);
}
private static WrapType getWrapType(final int wrap) {
@@ -1020,23 +804,19 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
}
}
private ASTNode processParenBlock(List<Block> result,
ASTNode child,
WrappingStrategy wrappingStrategy,
final boolean doAlign) {
private ASTNode processParenthesisBlock(List<Block> result, ASTNode child,WrappingStrategy wrappingStrategy, final boolean doAlign) {
myUseChildAttributes = true;
final IElementType from = JavaTokenType.LPARENTH;
final IElementType to = JavaTokenType.RPARENTH;
return processParenBlock(from, to, result, child, wrappingStrategy, doAlign);
return processParenthesisBlock(from, to, result, child, wrappingStrategy, doAlign);
}
private ASTNode processParenBlock(final IElementType from,
private ASTNode processParenthesisBlock(final IElementType from,
final IElementType to, final List<Block> result, ASTNode child,
final WrappingStrategy wrappingStrategy, final boolean doAlign
) {
@@ -1049,7 +829,6 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
boolean isAfterIncomplete = false;
ASTNode prev = child;
int startOffset = child.getTextRange().getStartOffset();
while (child != null) {
isAfterIncomplete = isAfterIncomplete || child.getElementType() == TokenType.ERROR_ELEMENT ||
child.getElementType() == JavaElementType.EMPTY_EXPRESSION;
@@ -1066,10 +845,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
}
else {
final IElementType elementType = child.getElementType();
result.add(createJavaBlock(child, mySettings, internalIndent,
wrappingStrategy.getWrap(elementType),
alignmentStrategy.getAlignment(elementType),
startOffset));
processChild(result, child, alignmentStrategy.getAlignment(elementType), wrappingStrategy.getWrap(elementType), internalIndent);
if (to == null) {//process only one statement
return child;
}
@@ -1077,7 +853,6 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
isAfterIncomplete = false;
}
prev = child;
startOffset += child.getTextLength();
child = child.getTreeNext();
}
@@ -1202,9 +977,31 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
return false;
}
protected abstract Wrap getReservedWrap(final IElementType elementType);
/**
* <b>Note:</b> this method is considered to be a legacy heritage and is assumed to be removed as soon as formatting processing
* is refactored
*
* @param elementType target element type
* @return <code>null</code> all the time
*/
public Wrap getReservedWrap(IElementType elementType) {
return null;
}
protected abstract void setReservedWrap(final Wrap reservedWrap, final IElementType operationType);
/**
* Defines contract for associating operation type and particular wrap instance. I.e. given wrap object <b>may</b> be returned
* from subsequent {@link #getReservedWrap(IElementType)} call if given operation type is used as an argument there.
* <p/>
* Default implementation ({@link AbstractJavaBlock#setReservedWrap(Wrap, IElementType)}) does nothing.
* <p/>
* <b>Note:</b> this method is considered to be a legacy heritage and is assumed to be removed as soon as formatting processing
* is refactored
*
* @param reservedWrap reserved wrap instance
* @param operationType target operation type to associate with the given wrap instance
*/
protected void setReservedWrap(final Wrap reservedWrap, final IElementType operationType) {
}
@Nullable
protected static ASTNode getTreeNode(final Block child2) {
@@ -71,7 +71,7 @@ public class BlockContainingJavaBlock extends AbstractJavaBlock{
}
}
private int calcNewState(final ASTNode child, final int state) {
private static int calcNewState(final ASTNode child, final int state) {
if (state == BEFORE_FIRST) {
if (child.getElementType() == ElementType.ELSE_KEYWORD) {
return AFTER_ELSE;
@@ -152,13 +152,13 @@ public class BlockContainingJavaBlock extends AbstractJavaBlock{
return Indent.getContinuationIndent();
}
private boolean isSimpleStatement(final ASTNode child) {
private static boolean isSimpleStatement(final ASTNode child) {
if (child.getElementType() == ElementType.BLOCK_STATEMENT) return false;
if (!ElementType.STATEMENT_BIT_SET.contains(child.getElementType())) return false;
return isStatement(child, child.getTreeParent());
}
private boolean isPartOfCodeBlock(final ASTNode child) {
private static boolean isPartOfCodeBlock(final ASTNode child) {
if (child == null) return false;
if (child.getElementType() == ElementType.BLOCK_STATEMENT) return true;
if (child.getElementType() == ElementType.CODE_BLOCK) return true;
@@ -168,12 +168,7 @@ public class BlockContainingJavaBlock extends AbstractJavaBlock{
return child.getElementType() == JavaDocElementType.DOC_COMMENT;
}
protected Wrap getReservedWrap(final IElementType elementType) {
return null;
}
protected void setReservedWrap(final Wrap reservedWrap, final IElementType operationType) {
}
@NotNull
public ChildAttributes getChildAttributes(final int newChildIndex) {
@@ -27,6 +27,7 @@ import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.impl.source.tree.StdTokenSets;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
@@ -97,6 +98,7 @@ public class CodeBlockBlock extends AbstractJavaBlock {
}
}
@Nullable
private ASTNode composeCodeBlock(final ArrayList<Block> result, ASTNode child, final Indent indent) {
final ArrayList<Block> localResult = new ArrayList<Block>();
processChild(localResult, child, null, null, Indent.getNoneIndent());
@@ -125,6 +127,7 @@ public class CodeBlockBlock extends AbstractJavaBlock {
return result;
}
@Nullable
private ASTNode processCaseAndStatementAfter(final ArrayList<Block> result,
ASTNode child,
final Alignment childAlignment,
@@ -159,7 +162,7 @@ public class CodeBlockBlock extends AbstractJavaBlock {
return null;
}
private boolean isBreakOrReturn(final ASTNode child) {
private static boolean isBreakOrReturn(final ASTNode child) {
IElementType elementType = child.getElementType();
return JavaElementType.BREAK_STATEMENT == elementType || JavaElementType.RETURN_STATEMENT == elementType;
}
@@ -193,7 +196,7 @@ public class CodeBlockBlock extends AbstractJavaBlock {
return result;
}
private int calcNewState(final ASTNode child, int state) {
private static int calcNewState(final ASTNode child, int state) {
switch (state) {
case BEFORE_FIRST: {
if (StdTokenSets.COMMENT_BIT_SET.contains(child.getElementType())) {
@@ -218,7 +221,7 @@ public class CodeBlockBlock extends AbstractJavaBlock {
return INSIDE_BODY;
}
private boolean isLBrace(final ASTNode child) {
private static boolean isLBrace(final ASTNode child) {
return child.getElementType() == ElementType.LBRACE;
}
@@ -250,7 +253,7 @@ public class CodeBlockBlock extends AbstractJavaBlock {
}
}
private boolean isRBrace(final ASTNode child) {
private static boolean isRBrace(final ASTNode child) {
return child.getElementType() == ElementType.RBRACE;
}
@@ -269,11 +272,4 @@ public class CodeBlockBlock extends AbstractJavaBlock {
}
}
}
protected Wrap getReservedWrap(final IElementType elementType) {
return null;
}
protected void setReservedWrap(final Wrap reservedWrap, final IElementType operationType) {
}
}
@@ -20,7 +20,6 @@ import com.intellij.lang.ASTNode;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.formatter.FormatterUtil;
import com.intellij.psi.impl.source.tree.ElementType;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@@ -48,13 +47,6 @@ public class DocCommentBlock extends AbstractJavaBlock{
}
protected Wrap getReservedWrap(final IElementType elementType) {
return null;
}
protected void setReservedWrap(final Wrap reservedWrap, final IElementType operationType) {
}
@NotNull
public ChildAttributes getChildAttributes(final int newChildIndex) {
return new ChildAttributes(Indent.getSpaceIndent(1), null);
@@ -23,7 +23,6 @@ import com.intellij.lang.ASTNode;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.formatter.FormatterUtil;
import com.intellij.psi.impl.source.tree.ElementType;
import com.intellij.psi.tree.IElementType;
import java.util.ArrayList;
import java.util.List;
@@ -77,11 +76,4 @@ public class ExtendsListBlock extends AbstractJavaBlock{
}
return false;
}
protected Wrap getReservedWrap(final IElementType elementType) {
return null;
}
protected void setReservedWrap(final Wrap reservedWrap, final IElementType operationType) {
}
}
@@ -0,0 +1,92 @@
/*
* Copyright 2000-2010 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.formatter.java;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiBinaryExpression;
import com.intellij.psi.TokenType;
import com.intellij.psi.impl.source.SourceTreeToPsiMap;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.Set;
import static java.util.Arrays.asList;
/**
* Contains various utility methods for <code>AST</code> processing during code formatting.
*
* @author Denis Zhdanov
* @since Apr 21, 2010 4:02:17 PM
*/
public class FormattingAstUtil {
/** Holds type of AST elements that are considered to be assignments. */
private static final Set<IElementType> ASSIGNMENT_ELEMENT_TYPES = new HashSet<IElementType>(asList(
JavaElementType.ASSIGNMENT_EXPRESSION, JavaElementType.LOCAL_VARIABLE, JavaElementType.FIELD
));
private FormattingAstUtil() {
}
/**
* Tries to get previous non-white space <code>AST</code> node for the given one.
*
* @param node base node which left non-white space sibling is to be found
* @return left non-white space sibling of the given node if any; <code>null</code> otherwise
*/
@Nullable
public static ASTNode getPrevElement(final ASTNode node) {
ASTNode result = node.getTreePrev();
while (result != null && result.getElementType() == TokenType.WHITE_SPACE) {
result = result.getTreePrev();
}
return result;
}
/**
* Allows to answer if given node wraps assignement operation.
*
* @param node node to check
* @return <code>true</code> if given node wraps assignement operation; <code>false</code> otherwise
*/
public static boolean isAssignment(ASTNode node) {
return ASSIGNMENT_ELEMENT_TYPES.contains(node.getElementType());
}
/**
* Allows to check if given <code>AST</code> nodes refer to binary expressions and have the same priority.
*
* @param node1 node to check
* @param node2 node to check
* @return <code>true</code> if given nodes are binary expressions and have the same priority;
* <code>false</code> otherwise
*/
public static boolean binaryExpressionHasTheSamePriority(ASTNode node1, ASTNode node2) {
if (node1 == null || node2 == null) {
return false;
}
if (node1.getElementType() != JavaElementType.BINARY_EXPRESSION || node2.getElementType() != JavaElementType.BINARY_EXPRESSION) {
return false;
}
PsiBinaryExpression expression1 = (PsiBinaryExpression)SourceTreeToPsiMap.treeElementToPsi(node1);
PsiBinaryExpression expression2 = (PsiBinaryExpression)SourceTreeToPsiMap.treeElementToPsi(node2);
return expression1.getOperationSign().getTokenType() == expression2.getOperationSign().getTokenType();
}
}
@@ -21,7 +21,6 @@ import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.formatter.FormatterUtil;
import com.intellij.psi.impl.source.tree.ElementType;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@@ -46,7 +45,7 @@ public class LabeledJavaBlock extends AbstractJavaBlock{
result.add(createJavaBlock(child, mySettings, currentIndent, currentWrap, null));
if (child.getElementType() == ElementType.COLON) {
currentIndent = Indent.getNoneIndent();
currentWrap =Wrap.createWrap(Wrap.ALWAYS, true);
currentWrap =Wrap.createWrap(WrapType.ALWAYS, true);
}
}
child = child.getTreeNext();
@@ -62,13 +61,6 @@ public class LabeledJavaBlock extends AbstractJavaBlock{
}
}
protected Wrap getReservedWrap(final IElementType elementType) {
return null;
}
protected void setReservedWrap(final Wrap reservedWrap, final IElementType operationType) {
}
@Override
@NotNull
public ChildAttributes getChildAttributes(final int newChildIndex) {
@@ -21,7 +21,6 @@ import com.intellij.formatting.Alignment;
import com.intellij.formatting.Indent;
import com.intellij.formatting.Block;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.tree.IElementType;
import java.util.List;
@@ -33,11 +32,4 @@ public class MethodCallExpressionBlock extends AbstractJavaBlock{
protected List<Block> buildChildren() {
return null;
}
protected Wrap getReservedWrap(final IElementType elementType) {
return null;
}
protected void setReservedWrap(final Wrap reservedWrap, final IElementType operationType) {
}
}
@@ -70,7 +70,7 @@ public class SimpleJavaBlock extends AbstractJavaBlock {
if (astNode != child && child != null) {
offset = child.getTextRange().getStartOffset();
}
if (indent != null && !(myNode.getPsi() instanceof PsiFile) && child.getElementType() != ElementType.MODIFIER_LIST) {
if (indent != null && !(myNode.getPsi() instanceof PsiFile) && child != null && child.getElementType() != ElementType.MODIFIER_LIST) {
indent = Indent.getContinuationIndent();
}
//indent = FormatterEx.getInstance().getContinuationIndent();
@@ -107,10 +107,12 @@ public class SimpleJavaBlock extends AbstractJavaBlock {
}
}
protected Wrap getReservedWrap(final IElementType elementType) {
@Override
public Wrap getReservedWrap(final IElementType elementType) {
return myReservedWrap.get(elementType);
}
@Override
protected void setReservedWrap(final Wrap reservedWrap, final IElementType operationType) {
myReservedWrap.put(operationType, reservedWrap);
}
@@ -0,0 +1,100 @@
/*
* Copyright 2000-2010 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.formatter.java.wrap;
import com.intellij.formatting.ASTBlock;
import com.intellij.formatting.Block;
import com.intellij.formatting.Wrap;
import com.intellij.lang.ASTNode;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.formatter.java.wrap.impl.JavaChildBlockWrapFactory;
import com.intellij.psi.formatter.java.wrap.impl.JavaChildWrapArranger;
import org.jetbrains.annotations.Nullable;
/**
* Defines common contract for {@link Wrap wraps} manipulation during java {@link Block blockes} processing
* <p/>
* This class is intended to serve as a facade for various fine-grained wrap processing classes.
* <p/>
* This class is not singleton but it's thread-safe and provides single-point-of-usage field {@link #INSTANCE}.
* <p/>
* Thread-safe.
*
* @author Denis Zhdanov
* @since Apr 21, 2010 2:19:17 PM
*/
public class JavaWrapManager {
/** Single-point-of-usage field. */
public static final JavaWrapManager INSTANCE = new JavaWrapManager();
private final JavaChildWrapArranger myChildArranger;
private final JavaChildBlockWrapFactory myChildBlockFactory;
/**
* Creates new <code>JavaWrapManager</code> object with default wrapping services.
*/
public JavaWrapManager() {
this(new JavaChildWrapArranger(), new JavaChildBlockWrapFactory());
}
public JavaWrapManager(JavaChildWrapArranger childWrapArranger, JavaChildBlockWrapFactory childBlockWrapFactory) {
myChildArranger = childWrapArranger;
myChildBlockFactory = childBlockWrapFactory;
}
/**
* Tries to define the wrap to use for the {@link Block block} for the given <code>'child'</code> node. It's assumed that
* given <code>'child'</code> node is descendant (direct or indirect) of the given <code>'parent'</code> node.
* I.e. <code>'parent'</code> node defines usage context for the <code>'child'</code> node.
*
* @param child child node which {@link Wrap wrap} is to be defined
* @param parent direct or indirect parent of the given <code>'child'</code> node. Defines usage context
* of <code>'child'</code> node processing
* @param settings code style settings to use during wrap definition
* @param suggestedWrap wrap suggested to use by clients of current class. I.e. those clients offer wrap to
* use based on their information about current processing state. However, it's possible
* that they don't know details of fine-grained wrap definition algorithm encapsulated
* at the current class. Hence, this method takes suggested wrap into consideration but
* is not required to use it all the time node based on the given parameters
* @param reservedWrapsProvider reserved {@code 'element type -> wrap instance'} mappings provider. <b>Note:</b> this
* argument is considered to be a part of legacy heritage and is intended to be removed as
* soon as formatting code refactoring is done
* @return wrap to use for the given <code>'child'</code> node if it's possible to define the one;
* <code>null</code> otherwise
*/
@Nullable
public Wrap arrangeChildWrap(ASTNode child, ASTNode parent, CodeStyleSettings settings, Wrap suggestedWrap,
ReservedWrapsProvider reservedWrapsProvider)
{
return myChildArranger.arrange(child, parent, settings, suggestedWrap, reservedWrapsProvider);
}
/**
* Creates {@link Wrap wrap} to be used with the children blocks of the the given block.
*
* @param block target block which sub-blocks should use wrap created by the current method
* @param settings code formatting settings to consider during wrap construction
* @param reservedWrapsProvider reserved {@code 'element type -> wrap instance'} mappings provider. <b>Note:</b> this
* argument is considered to be a part of legacy heritage and is intended to be removed as
* soon as formatting code refactoring is done
* @return wrap to use for the sub-blocks of the given block
*/
@Nullable
public Wrap createChildBlockWrap(ASTBlock block, CodeStyleSettings settings, ReservedWrapsProvider reservedWrapsProvider) {
return myChildBlockFactory.create(block, settings, reservedWrapsProvider);
}
}
@@ -0,0 +1,42 @@
/*
* Copyright 2000-2010 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.formatter.java.wrap;
import com.intellij.formatting.Wrap;
import com.intellij.psi.formatter.java.AbstractJavaBlock;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.Nullable;
/**
* Defines contract for using predefined reserved wraps.
* <p/>
* <b>Note:</b> this interface is introduced for encapsulating legacy {@link AbstractJavaBlock#getReservedWrap(IElementType)}
* method and most probably will be removed as soon as formatting stuff is refactored.
*
* @author Denis Zhdanov
* @since Apr 21, 2010 3:43:17 PM
*/
public interface ReservedWrapsProvider {
/**
* Allows to retrieve predefined {@link Wrap} object for the given element type if any.
*
* @param elementType target element type
* @return predefined wrap for the given element type if any; <code>null</code> otherwise
*/
@Nullable
Wrap getReservedWrap(IElementType elementType);
}
@@ -0,0 +1,94 @@
/*
* Copyright 2000-2010 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.formatter.java.wrap.impl;
import com.intellij.formatting.ASTBlock;
import com.intellij.formatting.Wrap;
import com.intellij.formatting.WrapType;
import com.intellij.lang.ASTNode;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.formatter.java.FormattingAstUtil;
import com.intellij.psi.formatter.java.wrap.ReservedWrapsProvider;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.Nullable;
/**
* Encapsulates algorithm of construction {@link Wrap wraps} for sub-blocks of particular {@link ASTBlock block} taking into
* consideration current formatting settings.
* <p/>
* Thread-safe.
*
* @author Denis Zhdanov
* @since Apr 21, 2010 4:49:49 PM
*/
public class JavaChildBlockWrapFactory {
/**
* Creates {@link Wrap wrap} to be used with the children blocks of the the given block.
*
* @param block target block which sub-blocks should use wrap created by the current method
* @param settings code formatting settings to consider during wrap construction
* @param reservedWrapsProvider reserved {@code 'element type -> wrap instance'} mappings provider. <b>Note:</b> this
* argument is considered to be a part of legacy heritage and is intended to be removed as
* soon as formatting code refactoring is done
* @return wrap to use for the sub-blocks of the given block
*/
@Nullable
public Wrap create(ASTBlock block, CodeStyleSettings settings, ReservedWrapsProvider reservedWrapsProvider) {
ASTNode node = block.getNode();
Wrap wrap = block.getWrap();
final IElementType nodeType = node.getElementType();
if (nodeType == JavaElementType.EXTENDS_LIST || nodeType == JavaElementType.IMPLEMENTS_LIST) {
return Wrap.createWrap(settings.EXTENDS_LIST_WRAP, false);
}
else if (nodeType == JavaElementType.BINARY_EXPRESSION) {
Wrap actualWrap = wrap != null ? wrap : reservedWrapsProvider.getReservedWrap(JavaElementType.BINARY_EXPRESSION);
if (actualWrap == null) {
return Wrap.createWrap(settings.BINARY_OPERATION_WRAP, false);
}
else {
if (!FormattingAstUtil.binaryExpressionHasTheSamePriority(node, node.getTreeParent())) {
return Wrap.createChildWrap(actualWrap, WrapType.byLegacyRepresentation(settings.BINARY_OPERATION_WRAP), false);
}
else {
return actualWrap;
}
}
}
else if (nodeType == JavaElementType.CONDITIONAL_EXPRESSION) {
return Wrap.createWrap(settings.TERNARY_OPERATION_WRAP, false);
}
else if (nodeType == JavaElementType.ASSERT_STATEMENT) {
return Wrap.createWrap(settings.ASSERT_STATEMENT_WRAP, false);
}
else if (nodeType == JavaElementType.FOR_STATEMENT) {
return Wrap.createWrap(settings.FOR_STATEMENT_WRAP, false);
}
else if (nodeType == JavaElementType.THROWS_LIST) {
return Wrap.createWrap(settings.THROWS_LIST_WRAP, true);
}
else if (nodeType == JavaElementType.CODE_BLOCK) {
return Wrap.createWrap(Wrap.NORMAL, false);
}
else if (FormattingAstUtil.isAssignment(node)) {
return Wrap.createWrap(settings.ASSIGNMENT_WRAP, true);
}
else {
return null;
}
}
}
@@ -0,0 +1,227 @@
/*
* Copyright 2000-2010 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.formatter.java.wrap.impl;
import com.intellij.formatting.Wrap;
import com.intellij.formatting.WrapType;
import com.intellij.lang.ASTNode;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.formatter.java.FormattingAstUtil;
import com.intellij.psi.formatter.java.wrap.JavaWrapManager;
import com.intellij.psi.formatter.java.wrap.ReservedWrapsProvider;
import com.intellij.psi.impl.source.tree.ChildRole;
import com.intellij.psi.impl.source.tree.CompositeElement;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.Nullable;
/**
* Encapsulates implementation of
* {@link JavaWrapManager#arrangeChildWrap(ASTNode, ASTNode, CodeStyleSettings, Wrap, ReservedWrapsProvider)}.
* <p/>
* Thread-safe.
*
* @author Denis Zhdanov
* @since Apr 21, 2010 2:30:29 PM
*/
public class JavaChildWrapArranger {
/**
* Provides implementation of {@link JavaWrapManager#arrangeChildWrap(ASTNode, ASTNode, CodeStyleSettings, Wrap, ReservedWrapsProvider)}
* method.
*
* @param child child node which {@link Wrap wrap} is to be defined
* @param parent direct or indirect parent of the given <code>'child'</code> node. Defines usage context
* of <code>'child'</code> node processing
* @param settings code style settings to use during wrap definition
* @param suggestedWrap wrap suggested to use by clients of current class. I.e. those clients offer wrap to
* use based on their information about current processing state. However, it's possible
* that they don't know details of fine-grained wrap definition algorithm encapsulated
* at the current class. Hence, this method takes suggested wrap into consideration but
* is not required to use it all the time node based on the given parameters
* @param reservedWrapsProvider reserved {@code 'element type -> wrap instance'} mappings provider. <b>Note:</b> this
* argument is considered to be a part of legacy heritage and is intended to be removed as
* soon as formatting code refactoring is done
* @return wrap to use for the given <code>'child'</code> node if it's possible to define the one;
* <code>null</code> otherwise
*/
@SuppressWarnings({"MethodMayBeStatic"})
@Nullable
public Wrap arrange(ASTNode child, ASTNode parent, CodeStyleSettings settings, Wrap suggestedWrap,
ReservedWrapsProvider reservedWrapsProvider)
{
final ASTNode directParent = child.getTreeParent();
int role = ((CompositeElement)directParent).getChildRole(child);
final IElementType nodeType = parent.getElementType();
if (nodeType == JavaElementType.BINARY_EXPRESSION) {
if (role == ChildRole.OPERATION_SIGN && !settings.BINARY_OPERATION_SIGN_ON_NEXT_LINE) return null;
if (role == ChildRole.ROPERAND && settings.BINARY_OPERATION_SIGN_ON_NEXT_LINE) return null;
return suggestedWrap;
}
final IElementType childType = child.getElementType();
if (childType == JavaElementType.EXTENDS_LIST || childType == JavaElementType.IMPLEMENTS_LIST) {
return Wrap.createWrap(settings.EXTENDS_KEYWORD_WRAP, true);
}
else if (childType == JavaElementType.THROWS_LIST) {
return Wrap.createWrap(settings.THROWS_KEYWORD_WRAP, true);
}
else if (nodeType == JavaElementType.EXTENDS_LIST || nodeType == JavaElementType.IMPLEMENTS_LIST) {
if (role == ChildRole.REFERENCE_IN_LIST) {
return suggestedWrap;
}
else {
return null;
}
}
else if (nodeType == JavaElementType.THROWS_LIST) {
if (role == ChildRole.REFERENCE_IN_LIST) {
return suggestedWrap;
}
else {
return null;
}
}
else if (nodeType == JavaElementType.CONDITIONAL_EXPRESSION) {
if (role == ChildRole.COLON && !settings.TERNARY_OPERATION_SIGNS_ON_NEXT_LINE) return null;
if (role == ChildRole.QUEST && !settings.TERNARY_OPERATION_SIGNS_ON_NEXT_LINE) return null;
if (role == ChildRole.THEN_EXPRESSION && settings.TERNARY_OPERATION_SIGNS_ON_NEXT_LINE) return null;
if (role == ChildRole.ELSE_EXPRESSION && settings.TERNARY_OPERATION_SIGNS_ON_NEXT_LINE) return null;
return suggestedWrap;
}
else if (FormattingAstUtil.isAssignment(parent)) {
if (role == ChildRole.INITIALIZER_EQ && settings.PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE) return suggestedWrap;
if (role == ChildRole.INITIALIZER_EQ && !settings.PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE) return null;
if (role == ChildRole.OPERATION_SIGN && settings.PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE) return suggestedWrap;
if (role == ChildRole.OPERATION_SIGN && !settings.PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE) return null;
if (role == ChildRole.INITIALIZER && !settings.PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE) return suggestedWrap;
if (role == ChildRole.INITIALIZER && settings.PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE) return null;
if (role == ChildRole.ROPERAND && !settings.PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE) return suggestedWrap;
if (role == ChildRole.ROPERAND && settings.PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE) return null;
if (role == ChildRole.CLOSING_SEMICOLON) return null;
//if (role == ChildRole.TYPE) return suggestedWrap;
return suggestedWrap;
}
else if (nodeType == JavaElementType.REFERENCE_EXPRESSION) {
if (role == ChildRole.DOT) {
return reservedWrapsProvider.getReservedWrap(JavaElementType.REFERENCE_EXPRESSION);
}
else {
return suggestedWrap;
}
}
else if (nodeType == JavaElementType.FOR_STATEMENT) {
if (role == ChildRole.FOR_INITIALIZATION || role == ChildRole.CONDITION || role == ChildRole.FOR_UPDATE) {
return suggestedWrap;
}
if (role == ChildRole.LOOP_BODY) {
final boolean dontWrap = (childType == JavaElementType.CODE_BLOCK || childType == JavaElementType.BLOCK_STATEMENT) &&
settings.BRACE_STYLE == CodeStyleSettings.END_OF_LINE;
return Wrap.createWrap(dontWrap ? WrapType.NONE : WrapType.NORMAL, true);
}
else {
return null;
}
}
else if (nodeType == JavaElementType.METHOD) {
if (role == ChildRole.THROWS_LIST) {
return suggestedWrap;
}
else {
return null;
}
}
else if (nodeType == JavaElementType.MODIFIER_LIST) {
if (childType == JavaElementType.ANNOTATION) {
return reservedWrapsProvider.getReservedWrap(JavaElementType.MODIFIER_LIST);
}
ASTNode prevElement = FormattingAstUtil.getPrevElement(child);
if (prevElement != null && prevElement.getElementType() == JavaElementType.ANNOTATION) {
return reservedWrapsProvider.getReservedWrap(JavaElementType.MODIFIER_LIST);
}
else {
return null;
}
}
else if (nodeType == JavaElementType.ASSERT_STATEMENT) {
if (role == ChildRole.CONDITION) {
return suggestedWrap;
}
if (role == ChildRole.ASSERT_DESCRIPTION && !settings.ASSERT_STATEMENT_COLON_ON_NEXT_LINE) {
return suggestedWrap;
}
if (role == ChildRole.COLON && settings.ASSERT_STATEMENT_COLON_ON_NEXT_LINE) {
return suggestedWrap;
}
return null;
}
else if (nodeType == JavaElementType.CODE_BLOCK) {
if (role == ChildRole.STATEMENT_IN_BLOCK) {
return suggestedWrap;
}
else {
return null;
}
}
else if (nodeType == JavaElementType.IF_STATEMENT) {
if (childType == JavaElementType.IF_STATEMENT && role == ChildRole.ELSE_BRANCH && settings.SPECIAL_ELSE_IF_TREATMENT) {
return Wrap.createWrap(WrapType.NONE, false);
}
if (role == ChildRole.THEN_BRANCH || role == ChildRole.ELSE_BRANCH) {
if (childType == JavaElementType.BLOCK_STATEMENT) {
return null;
}
else {
return Wrap.createWrap(WrapType.NORMAL, true);
}
}
}
else if (nodeType == JavaElementType.FOREACH_STATEMENT || nodeType == JavaElementType.WHILE_STATEMENT) {
if (role == ChildRole.LOOP_BODY) {
if (childType == JavaElementType.BLOCK_STATEMENT) {
return null;
}
else {
return Wrap.createWrap(WrapType.NORMAL, true);
}
}
}
else if (nodeType == JavaElementType.DO_WHILE_STATEMENT) {
if (role == ChildRole.LOOP_BODY) {
return Wrap.createWrap(WrapType.NORMAL, true);
} else if (role == ChildRole.WHILE_KEYWORD) {
return Wrap.createWrap(WrapType.NORMAL, true);
}
} else if (nodeType == JavaElementType.ANNOTATION_ARRAY_INITIALIZER) {
if (suggestedWrap != null) {
return suggestedWrap;
}
if (role == ChildRole.ANNOTATION_VALUE) {
return Wrap.createWrap(WrapType.NORMAL, true);
}
}
return suggestedWrap;
}
}
@@ -30,6 +30,7 @@ import com.intellij.psi.scope.ElementClassFilter;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.scope.processor.FilterScopeProcessor;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.CharTable;
@@ -112,7 +113,17 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo
PsiParameter parameter = parameters[j];
PsiType type1 = TypeConversionUtil.erasure(parameter.getType());
String type2 = signature[j];
if (!Comparing.strEqual(type1.getPresentableText(), type2) && !Comparing.strEqual(type1.getCanonicalText(), type2)) continue nextMethod;
if (!Comparing.strEqual(type1.getPresentableText(), type2) && !Comparing.strEqual(type1.getCanonicalText(), type2)) {
String shortName = "";
PsiClass psiClass = PsiUtil.resolveClassInType(type1);
while (psiClass != null) {
shortName = psiClass.getName() + (shortName.length() > 0 ? "." + shortName : "");
psiClass = PsiTreeUtil.getParentOfType(psiClass, PsiClass.class);
}
if (!Comparing.strEqual(shortName, type2)) {
continue nextMethod;
}
}
}
return new MyReference(method) {
@@ -91,6 +91,7 @@ public class CreateClassUtil {
else {
final FileTemplateManager fileTemplateManager = FileTemplateManager.getInstance();
FileTemplate fileTemplate = fileTemplateManager.getJ2eeTemplate(templateName);
LOG.assertTrue(fileTemplate != null, templateName + " not found");
final String text = fileTemplate.getText(attributes);
aClass = JavaCreateFromTemplateHandler.createClassOrInterface(project, directory, text, true, fileTemplate.getExtension());
}
@@ -28,6 +28,9 @@ import org.jetbrains.annotations.Nullable;
public class JavaInheritanceWeigher extends ProximityWeigher {
public Comparable weigh(@NotNull final PsiElement element, final ProximityLocation location) {
if (element instanceof PsiClass && isTooGeneral((PsiClass)element)) return false;
if (element instanceof PsiMethod && isTooGeneral(((PsiMethod)element).getContainingClass())) return false;
final PsiElement position = location.getPosition();
PsiClass placeClass = PsiTreeUtil.getContextOfType(element, PsiClass.class, false);
if (position.getParent() instanceof PsiReferenceExpression) {
@@ -43,9 +46,8 @@ public class JavaInheritanceWeigher extends ProximityWeigher {
}
}
if (element instanceof PsiClass && isTooGeneral((PsiClass)element)) return false;
if (element instanceof PsiMethod && isTooGeneral(((PsiMethod)element).getContainingClass())) return false;
if (placeClass == null) return false;
PsiClass contextClass = PsiTreeUtil.getContextOfType(position, PsiClass.class, false);
while (contextClass != null) {
PsiClass elementClass = placeClass;
@@ -84,5 +84,19 @@ public class MoveJavaFileHandler extends MoveFileHandler {
@Override
public void updateMovedFile(PsiFile file) throws IncorrectOperationException {
ChangeContextUtil.decodeContextInfo(file, null, null);
final PsiDirectory containingDirectory = file.getContainingDirectory();
if (containingDirectory != null) {
final PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(containingDirectory);
if (aPackage != null) {
final PsiPackageStatement packageStatement =
JavaPsiFacade.getElementFactory(file.getProject()).createPackageStatement(aPackage.getQualifiedName());
if (file instanceof PsiJavaFile) {
final PsiPackageStatement filePackageStatement = ((PsiJavaFile)file).getPackageStatement();
if (filePackageStatement != null) {
filePackageStatement.getPackageReference().replace(packageStatement.getPackageReference());
}
}
}
}
}
}
@@ -33,7 +33,8 @@ public class JavaMoveFilesOrDirectoriesHandler extends MoveFilesOrDirectoriesHan
allJava &= JavaCopyFilesOrDirectoriesHandler.hasPackages((PsiDirectory)element);
}
else if (element instanceof PsiFile) {
allJava &= element instanceof PsiJavaFile && !JspPsiUtil.isInJspFile(element) && !CollectHighlightsUtil.isOutsideSourceRootJavaFile((PsiJavaFile) element);
allJava &= element instanceof PsiJavaFile && !JspPsiUtil.isInJspFile(element) &&
((PsiJavaFile)element).getClasses().length > 0 && !CollectHighlightsUtil.isOutsideSourceRootJavaFile((PsiJavaFile) element);
}
else {
return false;
@@ -55,6 +56,6 @@ public class JavaMoveFilesOrDirectoriesHandler extends MoveFilesOrDirectoriesHan
@Override
public void doMove(Project project, PsiElement[] elements, PsiElement targetContainer, MoveCallback callback) {
super.doMove(project, elements, targetContainer, callback); //To change body of overridden methods use File | Settings | File Templates.
super.doMove(project, elements, targetContainer, callback);
}
}
@@ -0,0 +1,13 @@
class CSS {
static class IO{}
}
class TD {
void calculateSmth(CSS.IO io){}
}
/**
* @see TD#calculateSmth(CSS.IO)
*/
class Test {
}
@@ -90,6 +90,8 @@ public class JavadocHighlightingTest extends LightDaemonAnalyzerTestCase {
public void testVararg() throws Exception {doTest();}
public void testInnerClassReferenceInSignature() throws Exception {doTest();}
public void testBadReference() throws Exception{
doTest();
}
@@ -0,0 +1,79 @@
package com.intellij.codeInsight.javadoc;
import com.intellij.JavaTestUtil;
import com.intellij.codeInsight.CodeInsightTestCase;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.testFramework.PsiTestUtil;
import java.io.File;
import java.io.IOException;
/**
* @author yole
*/
public class JavaDocInfoGeneratorTest extends CodeInsightTestCase {
public void testSimpleField() throws Exception {
doTestField();
}
public void testFieldValue() throws Exception {
doTestField();
}
public void testValueInMethod() throws Exception {
doTestMethod();
}
public void testIdeadev2326() throws Exception {
doTestMethod();
}
public void testMethodTypeParameter() throws Exception {
doTestMethod();
}
public void testClassTypeParameter() throws Exception {
verifyJavaDoc(getTestClass());
}
private void doTestField() throws Exception {
PsiClass psiClass = getTestClass();
PsiField field = psiClass.getFields() [0];
verifyJavaDoc(field);
}
private void doTestMethod() throws Exception {
PsiClass psiClass = getTestClass();
PsiMethod method = psiClass.getMethods() [0];
verifyJavaDoc(method);
}
private PsiClass getTestClass() throws Exception{
configureByFile("/codeInsight/javadocIG/" + getTestName(true) + ".java");
return ((PsiJavaFile)myFile).getClasses() [0];
}
private void verifyJavaDoc(final PsiElement field) throws IOException {
final File htmlPath = new File(JavaTestUtil.getJavaTestDataPath() + "/codeInsight/javadocIG/" + getTestName(true) + ".html");
String htmlText = new String(FileUtil.loadFileText(htmlPath));
String docInfo = new JavaDocInfoGenerator(getProject(), field).generateDocInfo(null);
assertEquals(StringUtil.convertLineSeparators(htmlText.trim()), StringUtil.convertLineSeparators(docInfo.trim()));
}
public void testPackageInfo() throws Exception {
final String path = JavaTestUtil.getJavaTestDataPath() + "/codeInsight/javadocIG/";
final String packageInfo = path + getTestName(true);
PsiTestUtil.createTestProjectStructure(myProject, myModule, path, myFilesToDelete);
final String info =
new JavaDocInfoGenerator(getProject(), JavaPsiFacade.getInstance(getProject()).findPackage(getTestName(true))).generateDocInfo(null);
String htmlText = new String(FileUtil.loadFileText(new File(packageInfo + File.separator + "packageInfo.html")));
assertEquals(StringUtil.convertLineSeparators(htmlText.trim()), StringUtil.convertLineSeparators(info.trim()));
}
@Override
protected String getTestDataPath() {
return JavaTestUtil.getJavaTestDataPath();
}
}
@@ -34,7 +34,6 @@ public class JavaFormatterTest extends LightIdeaTestCase {
doTest("SCR915.java", "SCR915_after.java");
}
public void testForEach() throws Exception {
doTest("ForEach.java", "ForEach_after.java");
}
@@ -207,6 +206,35 @@ public class JavaFormatterTest extends LightIdeaTestCase {
doTest();
}
public void testNestedMethodsIndentation() throws Exception {
// Inspired by IDEA-43962
getSettings().getIndentOptions(StdFileTypes.JAVA).CONTINUATION_INDENT_SIZE = 4;
doMethodTest(
"BigDecimal.ONE\n" +
" .add(BigDecimal.ONE\n" +
" .add(BigDecimal.ONE\n" +
" .add(BigDecimal.ONE\n" +
" .add(BigDecimal.ONE\n" +
".add(BigDecimal.ONE\n" +
" .add(BigDecimal.ONE\n" +
" .add(BigDecimal.ONE\n" +
" .add(BigDecimal.ONE\n" +
" .add(BigDecimal.ONE)))))))));",
"BigDecimal.ONE\n" +
" .add(BigDecimal.ONE\n" +
" .add(BigDecimal.ONE\n" +
" .add(BigDecimal.ONE\n" +
" .add(BigDecimal.ONE\n" +
" .add(BigDecimal.ONE\n" +
" .add(BigDecimal.ONE\n" +
" .add(BigDecimal.ONE\n" +
" .add(BigDecimal.ONE\n" +
" .add(BigDecimal.ONE)))))))));"
);
}
public void testSwitch() throws Exception {
doTest();
}
@@ -2892,22 +2920,26 @@ public class JavaFormatterTest extends LightIdeaTestCase {
getSettings().ARRAY_INITIALIZER_WRAP = CodeStyleSettings.WRAP_ALWAYS;
getSettings().ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE = true;
getSettings().ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE = true;
doTextTest("public @interface Ann\n" +
doTextTest(
"public @interface Ann\n" +
"{\n" +
"int[] x = { 1, 2 };\n" +
"\n" +
"Mode[] modes () default { @Mode(value = 1), @Mode(value = 2) };\n" +
"}", "public @interface Ann {\n" +
" int[] x = {\n" +
" 1,\n" +
" 2\n" +
" };\n" +
"\n" +
" Mode[] modes() default {\n" +
" @Mode(value = 1),\n" +
" @Mode(value = 2)\n" +
" };\n" +
"}");
"}",
"public @interface Ann {\n" +
" int[] x = {\n" +
" 1,\n" +
" 2\n" +
" };\n" +
"\n" +
" Mode[] modes() default {\n" +
" @Mode(value = 1),\n" +
" @Mode(value = 2)\n" +
" };\n" +
"}"
);
}
private void doMethodTest(final String before, final String after) throws Exception {
@@ -78,4 +78,8 @@ public abstract class LookupElement extends UserDataHolderBase {
//noinspection unchecked
return aClass.isInstance(this) ? (T) this : null;
}
public boolean isCaseSensitive() {
return true;
}
}
@@ -112,6 +112,10 @@ public abstract class LookupElementDecorator<T extends LookupElement> extends Lo
final T t = super.as(aClass);
return t == null ? myDelegate.as(aClass) : t;
}
public boolean isCaseSensitive() {
return myDelegate.isCaseSensitive();
}
private static class InsertingDecorator<T extends LookupElement> extends LookupElementDecorator<T> {
private final InsertHandler<? super LookupElementDecorator<T>> myInsertHandler;
@@ -15,8 +15,6 @@
*/
package com.intellij.formatting;
import com.intellij.openapi.diagnostic.Logger;
/**
* The wrap setting for a formatting model block. Indicates the conditions under which a line break
* is inserted before the block when formatting, if the block extends beyond the
@@ -34,15 +32,46 @@ public abstract class Wrap {
private static WrapFactory myFactory;
/**
* @deprecated use {@link WrapType#ALWAYS} instead
*/
@Deprecated
public static WrapType ALWAYS = WrapType.ALWAYS;
/**
* @deprecated use {@link WrapType#NORMAL} instead
*/
@Deprecated
public static WrapType NORMAL = WrapType.NORMAL;
/**
* @deprecated use {@link WrapType#NONE} instead
*/
@Deprecated
public static WrapType NONE = WrapType.NONE;
/**
* @deprecated use {@link WrapType#CHOP_DOWN_IF_LONG} instead
*/
@SuppressWarnings({"UnusedDeclaration"})
@Deprecated
public static WrapType CHOP_DOWN_IF_LONG = WrapType.CHOP_DOWN_IF_LONG;
static void setFactory(WrapFactory factory) {
myFactory = factory;
}
/**
* Creates a block wrap setting of the legacy representation of specified wrap type (see {@link WrapType#getLegacyRepresentation()}).
*
* @param type the type of the wrap setting.
* @param wrapFirstElement if <code>true</code>, the first element in a sequence of elements of the same type is also wrapped.
* @return the wrap setting instance.
*/
public static Wrap createWrap(final int type, final boolean wrapFirstElement) {
return myFactory.createWrap(WrapType.byLegacyRepresentation(type), wrapFirstElement);
}
/**
* Creates a block wrap setting of the specified type.
*
@@ -15,6 +15,11 @@
*/
package com.intellij.formatting;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import java.util.HashMap;
import java.util.Map;
/**
* Defines possible types of a wrap.
*
@@ -23,29 +28,69 @@ package com.intellij.formatting;
*/
public enum WrapType {
/**
* A line break is always inserted before the start of the element.
* This corresponds to the "Wrap always" setting in Global Code Style | Wrapping.
*/
ALWAYS,
ALWAYS(CodeStyleSettings.WRAP_ALWAYS),
/**
* A line break is inserted before the start of the element if the right edge
* of the element goes beyond the specified wrap margin.
* This corresponds to the "Wrap if long" setting in Global Code Style | Wrapping.
*/
NORMAL,
NORMAL(CodeStyleSettings.WRAP_AS_NEEDED),
/**
* A line break is never inserted before the start of the element.
* This corresponds to the "Do not wrap" setting in Global Code Style | Wrapping.
*/
NONE,
NONE(CodeStyleSettings.DO_NOT_WRAP),
/**
* A line break is inserted before the start of the element if it is a part
* of list of elements of the same type and at least one of the elements was wrapped.
* This corresponds to the "Chop down if long" setting in Global Code Style | Wrapping.
*/
CHOP_DOWN_IF_LONG
CHOP_DOWN_IF_LONG(CodeStyleSettings.WRAP_ON_EVERY_ITEM);
private static final Map<Integer, WrapType> LEGACY_MAPPINGS = new HashMap<Integer, WrapType>();
static {
for (WrapType wrapType : values()) {
LEGACY_MAPPINGS.put(wrapType.getLegacyRepresentation(), wrapType);
}
}
private final int myLegacyRepresentation;
WrapType(int legacyRepresentation) {
myLegacyRepresentation = legacyRepresentation;
}
/**
* Allows to retrieve wrap type by it's legacy non-type-safe representation (see {@link #getLegacyRepresentation()}).
*
* @param value legacy representation of the target wrap type
* @return wrap type which {@link #getLegacyRepresentation() legacyRepresentation} is equal to the given value if any;
* {@link #CHOP_DOWN_IF_LONG} otherwise
*/
public static WrapType byLegacyRepresentation(int value) {
WrapType result = LEGACY_MAPPINGS.get(value);
return result == null ? CHOP_DOWN_IF_LONG : result;
}
/**
* Wrapping types were used as a primitive constants during this enum introduction (e.g. {@link CodeStyleSettings#DO_NOT_WRAP} etc).
* <p/>
* It's possible to map that legacy representation to the object-level enum member via {@link #byLegacyRepresentation(int)}.
* <p/>
* Current getter exposes legacy value associated with the current object-level wrap type representation.
*
* @return legacy representation of the current wrap type
*/
public int getLegacyRepresentation() {
return myLegacyRepresentation;
}
}
@@ -17,6 +17,7 @@ package com.intellij.psi;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.KeyedExtensionCollector;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@@ -37,7 +38,7 @@ public class WeighingService {
@NotNull
public static <T,Loc> WeighingComparable<T,Loc> weigh(Key<? extends Weigher<T,Loc>> key, T element, Loc location) {
final List<Weigher> weighers = COLLECTOR.forKey(key);
return new WeighingComparable<T,Loc>(element, location, weighers.toArray(new Weigher[weighers.size()]));
return new WeighingComparable<T,Loc>(element, location, ContainerUtil.toArray(weighers, new Weigher[weighers.size()]));
}
}
@@ -30,6 +30,7 @@ import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -42,7 +43,7 @@ import java.util.Set;
* @author peter
*/
public class FileContentUtil {
public static final String FORCE_RELOAD_REQUESTOR = "FileContentUtil.saveOrReload";
@NonNls public static final String FORCE_RELOAD_REQUESTOR = "FileContentUtil.saveOrReload";
private FileContentUtil() {
}
@@ -67,23 +68,23 @@ public class FileContentUtil {
}
public static void reparseFiles(@NotNull final Project project, @NotNull final Collection<VirtualFile> files, boolean includeOpenFiles) {
final Set<VFilePropertyChangeEvent> list = new THashSet<VFilePropertyChangeEvent>();
final Set<VFilePropertyChangeEvent> events = new THashSet<VFilePropertyChangeEvent>();
for (VirtualFile file : files) {
saveOrReload(file, list);
saveOrReload(file, events);
}
if (includeOpenFiles) {
for (VirtualFile open : FileEditorManager.getInstance(project).getOpenFiles()) {
if (!files.contains(open)) {
saveOrReload(open, list);
saveOrReload(open, events);
}
}
}
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
ApplicationManager.getApplication().getMessageBus().syncPublisher(VirtualFileManager.VFS_CHANGES)
.before(new ArrayList<VFileEvent>(list));
.before(new ArrayList<VFileEvent>(events));
ApplicationManager.getApplication().getMessageBus().syncPublisher(VirtualFileManager.VFS_CHANGES)
.after(new ArrayList<VFileEvent>(list));
.after(new ArrayList<VFileEvent>(events));
}
});
}
@@ -16,6 +16,8 @@
package com.intellij.application.options.colors;
import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
import com.intellij.codeInsight.daemon.impl.SeveritiesProvider;
import com.intellij.openapi.editor.colors.CodeInsightColors;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
@@ -82,5 +84,12 @@ public class ColorSettingsUtil {
descriptors.add(new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.info"), CodeInsightColors.INFO_ATTRIBUTES));
descriptors.add(new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.server.problems"), CodeInsightColors.GENERIC_SERVER_ERROR_OR_WARNING));
descriptors.add(new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.server.duplicate"), CodeInsightColors.DUPLICATE_FROM_SERVER));
for (SeveritiesProvider provider : Extensions.getExtensions(SeveritiesProvider.EP_NAME)) {
for (HighlightInfoType highlightInfoType : provider.getSeveritiesHighlightInfoTypes()) {
final TextAttributesKey attributesKey = highlightInfoType.getAttributesKey();
descriptors.add(new AttributesDescriptor(attributesKey.myExternalName, attributesKey));
}
}
}
}
@@ -7,8 +7,6 @@ package com.intellij.codeInsight.completion.impl;
import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.codeInsight.completion.PrefixMatcher;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.codeInsight.lookup.LookupItem;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.codeStyle.NameUtil;
import com.intellij.util.containers.hash.LinkedHashMap;
@@ -62,12 +60,7 @@ public class CamelHumpMatcher extends PrefixMatcher {
public boolean prefixMatches(@NotNull final LookupElement element) {
final LookupItem item = element.as(LookupItem.class); //must die, use LookupElementBuilder or CompletionResultSet.caseInsensitive
final LookupElementBuilder builder = element.as(LookupElementBuilder.class);
boolean itemCaseInsensitive = item != null && Boolean.TRUE.equals(item.getAttribute(LookupItem.CASE_INSENSITIVE)) ||
builder != null && !builder.isCaseSensitive();
return prefixMatchersInternal(element, itemCaseInsensitive);
return prefixMatchersInternal(element, !element.isCaseSensitive());
}
private boolean prefixMatchersInternal(final LookupElement element, final boolean itemCaseInsensitive) {
@@ -316,6 +316,12 @@ public class DocumentationManager {
component.setHint(hint);
if (myEditor == null) {
// subsequent invocation of javadoc popup from completion will have myEditor == null because of cancel invoked,
// so reevaluate the editor for proper popup placement
Lookup lookup = LookupManager.getInstance(myProject).getActiveLookup();
myEditor = lookup != null ? lookup.getEditor() : null;
}
fetchDocInfo(getDefaultCollector(element, originalElement), component);
myDocInfoHintRef = new WeakReference<JBPopup>(hint);
@@ -359,4 +359,16 @@ public class LookupItem<T> extends MutableLookupElement<T> implements Comparable
myAttributes.putAll(item.myAttributes);
}
@Override
public boolean isCaseSensitive() {
return !Boolean.TRUE.equals(getAttribute(CASE_INSENSITIVE));
}
public static @Nullable LookupItem from(LookupElement lookupElement) {
if (lookupElement instanceof LookupElementDecorator) {
lookupElement = ((LookupElementDecorator)lookupElement).getDelegate();
}
if (lookupElement instanceof LookupItem) return (LookupItem)lookupElement;
return null;
}
}
@@ -29,7 +29,9 @@ public interface CustomLiveTemplate {
@Nullable
String computeTemplateKey(@NotNull CustomTemplateCallback callback);
boolean isApplicable(PsiFile file, int offset, boolean selection);
boolean isApplicable(PsiFile file, int offset);
boolean supportsWrapping();
void expand(String key, @NotNull CustomTemplateCallback callback);
@@ -18,12 +18,14 @@ package com.intellij.codeInsight.template;
import com.intellij.codeInsight.template.impl.TemplateImpl;
import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
import com.intellij.codeInsight.template.impl.TemplateSettings;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileFactory;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.util.LocalTimeCounter;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NotNull;
@@ -61,8 +63,7 @@ public class CustomTemplateCallback {
@Nullable
public PsiElement getContext() {
int offset = myStartOffset;
return myFile.findElementAt(offset > 0 ? offset - 1 : offset);
return getContext(myFile, myStartOffset > 0 ? myStartOffset - 1 : myStartOffset);
}
public void fixInitialState() {
@@ -229,4 +230,18 @@ public class CustomTemplateCallback {
int caretAt = myEditor.getCaretModel().getOffset();
myEditor.getDocument().deleteString(caretAt - key.length(), caretAt);
}
public static PsiElement getContext(PsiFile file, int offset) {
PsiElement element = null;
if (!InjectedLanguageManager.getInstance(file.getProject()).isInjectedFragment(file)) {
element = InjectedLanguageUtil.findInjectedElementNoCommit(file, offset);
}
if (element == null) {
element = file.findElementAt(offset > 0 ? offset - 1 : offset);
if (element == null) {
element = file;
}
}
return element;
}
}
@@ -77,7 +77,7 @@ public class SurroundWithTemplateHandler implements CodeInsightActionHandler {
List<CustomLiveTemplate> result = new ArrayList<CustomLiveTemplate>();
int offset = editor.getCaretModel().getOffset();
for (CustomLiveTemplate template : CustomLiveTemplate.EP_NAME.getExtensions()) {
if (template.isApplicable(file, offset, true)) {
if (template.supportsWrapping() && template.isApplicable(file, offset)) {
result.add(template);
}
}
@@ -244,7 +244,7 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo
for (final CustomLiveTemplate customLiveTemplate : CustomLiveTemplate.EP_NAME.getExtensions()) {
if (shortcutChar == customLiveTemplate.getShortcut()) {
int caretOffset = editor.getCaretModel().getOffset();
if (customLiveTemplate.isApplicable(file, caretOffset, false)) {
if (customLiveTemplate.isApplicable(file, caretOffset)) {
final CustomTemplateCallback callback = new CustomTemplateCallback(editor, file);
String key = customLiveTemplate.computeTemplateKey(callback);
if (key != null) {
@@ -125,7 +125,7 @@ public abstract class AbstractBlockWrapper {
}
/**
* Calculates indent for the given block and target start offset according to the given idnent options.
* Calculates indent for the given block and target start offset according to the given indent options.
*
* @param options indent options to use
* @param block target wrapped block
@@ -255,18 +255,13 @@ public abstract class AbstractBlockWrapper {
return indent.add(getWhiteSpace());
}
else {
ArrayList<IndentData> ignored = new ArrayList<IndentData>();
IndentData offsetFromParent = myParent.getChildOffset(this, indentOption, -1);
IndentData result = indent.add(offsetFromParent);
if (!ignored.isEmpty()) {
result = result.add(ignored.get(ignored.size() - 1));
}
return result;
return indent.add(offsetFromParent);
}
}
private IndentData getIndent(final CodeStyleSettings.IndentOptions options, final int index, IndentImpl indent) {
private static IndentData getIndent(final CodeStyleSettings.IndentOptions options, final int index, IndentImpl indent) {
if (indent.getType() == IndentImpl.Type.CONTINUATION) {
return new IndentData(options.CONTINUATION_INDENT_SIZE);
}
@@ -292,7 +287,7 @@ public abstract class AbstractBlockWrapper {
* value is defined (not <code>null</code>).
* <p/>
* This property is used later during
* {@link LeafBlockWrapper#calculateOffset(CodeStyleSettings.IndentOptions) leaf block offset calculation}.
* {@link LeafBlockWrapper#calculateOffset(CodeStyleSettings.IndentOptions)} leaf block offset calculation}.
*
* @param indentFromParent indent value to apply
*/
@@ -340,4 +335,9 @@ public abstract class AbstractBlockWrapper {
myParent = null;
myWhiteSpace = null;
}
@Override
public String toString() {
return getClass().getName() + "(" + myStart + "-" + myEnd + ")";
}
}
@@ -629,9 +629,9 @@ class FormatProcessor {
}
/**
* Tries to get align-implied indent of the line that contains current block.
* Tries to get align-implied indent of the current block.
*
* @return indent of the line that contains current block if any; <code>null</code> otherwise
* @return indent of the current block if any; <code>null</code> otherwise
*/
@Nullable
private IndentData getAlignOffset() {
@@ -279,8 +279,7 @@ public class FormatterImpl extends FormatterEx
{
boolean wsContainsCaret = whiteSpace.getStartOffset() <= offset && offset < whiteSpace.getEndOffset();
final CharSequence text = getCharSequence(documentModel);
int lineStartOffset = getLineStartOffset(offset, whiteSpace, text, documentModel);
int lineStartOffset = getLineStartOffset(offset, whiteSpace, documentModel);
final IndentInfo indent = calcIndent(offset, documentModel, processor, whiteSpace);
@@ -325,7 +324,7 @@ public class FormatterImpl extends FormatterEx
final WhiteSpace whiteSpace = blockAfterOffset.getWhiteSpace();
final IndentInfo indent = calcIndent(offset, documentModel, processor, whiteSpace);
return indent.generateNewWhiteSpace(indentOptions).toString();
return indent.generateNewWhiteSpace(indentOptions);
}
return null;
}
@@ -355,10 +354,10 @@ public class FormatterImpl extends FormatterEx
private static int getLineStartOffset(final int offset,
final WhiteSpace whiteSpace,
final CharSequence text,
final FormattingDocumentModel documentModel) {
int lineStartOffset = offset;
CharSequence text = getCharSequence(documentModel);
lineStartOffset = CharArrayUtil.shiftBackwardUntil(text, lineStartOffset, " \t\n");
if (lineStartOffset > whiteSpace.getStartOffset()) {
if (lineStartOffset >= text.length()) lineStartOffset = text.length() - 1;
@@ -572,10 +571,6 @@ public class FormatterImpl extends FormatterEx
return myContinutationWithoutFirstIndent;
}
public static int getLineFeedsToModified(final FormattingDocumentModel model, final int offset, final int startOffset) {
return model.getLineNumber(offset) - model.getLineNumber(startOffset);
}
private final Object DISABLING_LOCK = new Object();
public boolean isDisabled() {
@@ -20,8 +20,6 @@ import com.intellij.openapi.util.TextRange;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
class LeafBlockWrapper extends AbstractBlockWrapper {
private static final int CONTAIN_LINE_FEEDS = 4;
private static final int READ_ONLY = 8;
@@ -149,12 +147,7 @@ class LeafBlockWrapper extends AbstractBlockWrapper {
}
}
ArrayList<IndentData> ignored = new ArrayList<IndentData>();
IndentData result = myParent.getChildOffset(this, options, this.getStartOffset());
if (!ignored.isEmpty()) {
result = result.add(ignored.get(ignored.size() - 1));
}
return result;
return myParent.getChildOffset(this, options, this.getStartOffset());
}
public void setSpaceProperty(final SpacingImpl currentSpaceProperty) {
@@ -191,8 +184,4 @@ class LeafBlockWrapper extends AbstractBlockWrapper {
return new TextRange(myStart, myEnd);
}
@Override
public String toString() {
return "LeafBlockWrapper(" + myStart + "-" + myEnd + ")";
}
}
@@ -33,8 +33,10 @@ import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootEvent;
import com.intellij.openapi.roots.ModuleRootListener;
import com.intellij.openapi.roots.ui.configuration.ProjectSettingsService;
import com.intellij.openapi.ui.Splitter;
import com.intellij.openapi.util.IconLoader;
import com.intellij.pom.Navigatable;
import com.intellij.ui.*;
import com.intellij.ui.content.Content;
import com.intellij.ui.treeStructure.Tree;
@@ -352,6 +354,7 @@ public class ModulesDependenciesPanel extends JPanel implements ModuleRootListen
group.add(actionManager.createExpandAllAction(treeExpander, tree));
}
group.add(actionManager.createCollapseAllAction(treeExpander, tree));
group.add(ActionManager.getInstance().getAction(IdeActions.ACTION_EDIT_SOURCE));
group.add(ActionManager.getInstance().getAction(IdeActions.MODULE_SETTINGS));
appendDependenciesAction(group);
return group;
@@ -406,7 +409,7 @@ public class ModulesDependenciesPanel extends JPanel implements ModuleRootListen
TreeUtil.selectFirstNode(myLeftTree);
}
private static class MyUserObject{
private static class MyUserObject implements Navigatable{
private boolean myInCycle;
private final Module myModule;
@@ -438,6 +441,18 @@ public class ModulesDependenciesPanel extends JPanel implements ModuleRootListen
public String toString() {
return myModule.getName();
}
public void navigate(boolean requestFocus) {
ProjectSettingsService.getInstance(myModule.getProject()).openModuleSettings(myModule);
}
public boolean canNavigate() {
return myModule != null && !myModule.isDisposed();
}
public boolean canNavigateToSource() {
return false;
}
}
private static class MyTreePanel extends JPanel implements DataProvider{
@@ -466,6 +481,15 @@ public class ModulesDependenciesPanel extends JPanel implements ModuleRootListen
if (PlatformDataKeys.HELP_ID.is(dataId)) {
return ourHelpID;
}
if (PlatformDataKeys.NAVIGATABLE.is(dataId)) {
final TreePath selectionPath = myTree.getLeadSelectionPath();
if (selectionPath != null && selectionPath.getLastPathComponent() instanceof DefaultMutableTreeNode){
DefaultMutableTreeNode node = (DefaultMutableTreeNode)selectionPath.getLastPathComponent();
if (node.getUserObject() instanceof MyUserObject){
return node.getUserObject();
}
}
}
return null;
}
}
@@ -18,6 +18,7 @@ package com.intellij.packageDependencies.ui;
import com.intellij.analysis.AnalysisScopeBundle;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.ui.configuration.ProjectSettingsService;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.PsiFile;
@@ -40,6 +41,21 @@ public class ModuleNode extends PackageDependenciesNode {
}
}
@Override
public boolean canNavigate() {
return myModule != null && !myModule.isDisposed();
}
@Override
public boolean canNavigateToSource() {
return false;
}
@Override
public void navigate(boolean focus) {
ProjectSettingsService.getInstance(myModule.getProject()).openModuleSettings(myModule);
}
public Icon getOpenIcon() {
return myModule == null ? null : myModule.getModuleType().getNodeIcon(true);
}
@@ -19,10 +19,12 @@ import com.intellij.lang.ASTFactory;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.TokenType;
import com.intellij.psi.impl.source.SourceTreeToPsiMap;
import com.intellij.psi.impl.source.tree.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.util.CharTable;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Nullable;
@@ -248,4 +250,22 @@ public class FormatterUtil {
return true;
}
public static boolean isPrecededBy(ASTNode node, IElementType eType) {
ASTNode prevNode = node.getTreePrev();
while (prevNode != null && prevNode.getPsi() instanceof PsiWhiteSpace) {
prevNode = prevNode.getTreePrev();
}
if (prevNode == null) return false;
return prevNode.getElementType() == eType;
}
public static boolean isPrecededBy(ASTNode node, TokenSet tokens) {
ASTNode prevNode = node.getTreePrev();
while (prevNode != null && prevNode.getPsi() instanceof PsiWhiteSpace) {
prevNode = prevNode.getTreePrev();
}
if (prevNode == null) return false;
return tokens.contains(prevNode.getElementType());
}
}
@@ -0,0 +1,72 @@
/*
* Copyright 2000-2010 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.formatter;
import com.intellij.formatting.Wrap;
import com.intellij.formatting.WrapType;
import com.intellij.lang.ASTNode;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.tree.IElementType;
/**
* Misc. code wrapping functions
* @author rvishnyakov
*/
public class WrappingUtil {
private WrappingUtil() {
}
public static boolean shouldWrap(int setting) {
return setting != CodeStyleSettings.DO_NOT_WRAP;
}
public static Wrap createWrap(int setting) {
return Wrap.createWrap(getWrapType(setting), true);
}
public static WrapType getWrapType(int setting) {
switch (setting) {
case CodeStyleSettings.WRAP_ALWAYS:
return WrapType.ALWAYS;
case CodeStyleSettings.WRAP_AS_NEEDED:
return WrapType.NORMAL;
case CodeStyleSettings.DO_NOT_WRAP:
return WrapType.NONE;
default:
return WrapType.CHOP_DOWN_IF_LONG;
}
}
public static WrapType getArrayInitializerWrapType(CodeStyleSettings settings,
ASTNode node,
IElementType lBraceType,
IElementType rBraceType) {
WrapType wrapType = WrapType.NONE;
if (shouldWrap(settings.ARRAY_INITIALIZER_WRAP)) {
if (node.getElementType() == rBraceType) {
wrapType = settings.ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE ? Wrap.ALWAYS : Wrap.NONE;
}
else if (FormatterUtil.isPrecededBy(node, lBraceType)) {
wrapType = settings.ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE ? Wrap.ALWAYS : Wrap.NONE;
}
else {
wrapType = WrappingUtil.getWrapType(settings.ARRAY_INITIALIZER_WRAP);
}
}
return wrapType;
}
}
@@ -67,16 +67,33 @@ public class ChangeList {
myChangeSetDepth++;
if (myChangeSetDepth > 1) return;
doBeginChangeSet();
}
private void doBeginChangeSet() {
myCurrentChangeSet = new ChangeSet(myStorage.nextId(), Clock.getCurrentTimestamp());
myCurrentBlock.add(myCurrentChangeSet);
}
public synchronized boolean forceBeginChangeSet() {
boolean split = myChangeSetDepth > 0;
if (split) doEndChangeSet(null);
myChangeSetDepth++;
doBeginChangeSet();
return split;
}
public synchronized boolean endChangeSet(String name) {
assert myChangeSetDepth > 0;
myChangeSetDepth--;
if (myChangeSetDepth > 0) return false;
return doEndChangeSet(name);
}
private boolean doEndChangeSet(String name) {
if (myCurrentChangeSet.getChanges().isEmpty()) {
myCurrentBlock.removeLast();
return false;
@@ -144,7 +161,7 @@ public class ChangeList {
}
private void flushChanges(boolean force) {
if (myChangeSetDepth > 0) return;
if (myChangeSetDepth > 0) return;
if (myCurrentBlock.shouldFlush(force) || flushEveryChangeSetInTests()) {
myStorage.writeNextBlock(myCurrentBlock);
myCurrentBlock = myStorage.createNewBlock();
@@ -140,7 +140,7 @@ public class ChangeListStorageImpl implements ChangeListStorage {
}
public synchronized List<ChangeSetBlock> purge(long period, int intervalBetweenActivities) {
List<ChangeSetBlock> result = new ArrayList<ChangeSetBlock>();
List<ChangeSetBlock> result = new ArrayList<ChangeSetBlock>(); // todo : do not collect changesets
int each = findFirstObsoleteBlock(period, intervalBetweenActivities);
try {
while(each != 0) {
@@ -155,7 +155,6 @@ public class ChangeListStorageImpl implements ChangeListStorage {
return result;
}
private int findFirstObsoleteBlock(long period, int intervalBetweenActivities) {
long prevTimestamp = 0;
long length = 0;
@@ -178,8 +177,7 @@ public class ChangeListStorageImpl implements ChangeListStorage {
return 0;
}
public void flush() {
public synchronized void flush() {
myStorage.flushSome();
}
}
@@ -23,7 +23,7 @@ import java.io.File;
import java.io.IOException;
public class LinkedRecordsTable extends AbstractRecordsTable {
private static final int VERSION = 3;
private static final int VERSION = 4;
private static final int ID_COUNTER_OFFSET = DEFAULT_HEADER_SIZE;
private static final int FIRST_RECORD_OFFSET = ID_COUNTER_OFFSET + 8;
@@ -62,6 +62,13 @@ public class LinkedRecordsTable extends AbstractRecordsTable {
return ZEROS;
}
@Override
protected void clearDeletedRecord(int record) {
setTimestamp(record, 0);
setNextRecord(record, 0);
setPrevRecord(record, 0);
}
public void setFSTimestamp(long timestamp) {
markDirty();
myStorage.putLong(FS_TIMESTAMP_OFFSET, timestamp);
@@ -77,7 +84,6 @@ public class LinkedRecordsTable extends AbstractRecordsTable {
}
public int getFirstRecord() {
markDirty();
return myStorage.getInt(FIRST_RECORD_OFFSET);
}
@@ -87,7 +93,6 @@ public class LinkedRecordsTable extends AbstractRecordsTable {
}
public int getLastRecord() {
markDirty();
return myStorage.getInt(LAST_RECORD_OFFSET);
}
@@ -55,6 +55,12 @@ public class LinkedStorage extends AbstractStorage {
}
}
public int getFirstRecord() {
synchronized (myLock) {
return ((LinkedRecordsTable)myRecordsTable).getFirstRecord();
}
}
public int getLastRecord() {
synchronized (myLock) {
return ((LinkedRecordsTable)myRecordsTable).getLastRecord();
@@ -67,6 +73,12 @@ public class LinkedStorage extends AbstractStorage {
}
}
public int getNextRecord(int record) {
synchronized (myLock) {
return ((LinkedRecordsTable)myRecordsTable).getNextRecord(record);
}
}
public long getTimestamp(int record) {
synchronized (myLock) {
return ((LinkedRecordsTable)myRecordsTable).getTimestamp(record);
@@ -46,6 +46,12 @@ public class LocalHistoryFacade {
myChangeList.beginChangeSet();
}
public void forceBeginChangeSet() {
if (myChangeList.forceBeginChangeSet()) {
fireChangeSetFinished();
}
}
public void endChangeSet(String name) {
if (myChangeList.endChangeSet(name)) {
fireChangeSetFinished();
@@ -51,8 +51,8 @@ public class StreamUtil {
}
public static Change readChange(DataInput in) throws IOException {
switch (in.readInt()) {
case 0:
int type = in.readInt();
switch (type) {
case 1:
return new CreateFileChange(in);
case 2:
@@ -72,14 +72,13 @@ public class StreamUtil {
case 9:
return new PutSystemLabelChange(in);
}
throw new IOException();
throw new IOException("unexpected change type: " + type);
}
public static void writeChange(DataOutput out, Change change) throws IOException {
int id = -1;
Class c = change.getClass();
if (c.equals(ChangeSet.class)) id = 0;
if (c.equals(CreateFileChange.class)) id = 1;
if (c.equals(CreateDirectoryChange.class)) id = 2;
if (c.equals(ContentChange.class)) id = 3;
@@ -90,7 +89,7 @@ public class StreamUtil {
if (c.equals(PutLabelChange.class)) id = 8;
if (c.equals(PutSystemLabelChange.class)) id = 9;
assert id != -1;
if (id == -1) throw new IOException("unexpected change type: " + c);
out.writeInt(id);
change.write(out);
@@ -30,9 +30,7 @@ public class LocalHistoryEventDispatcher extends VirtualFileAdapter implements V
private static final Key<Boolean> WAS_VERSIONED_KEY = Key.create(LocalHistoryEventDispatcher.class.getSimpleName() + ".WAS_VERSIONED_KEY");
private final LocalHistoryFacade myVcs;
private final IdeaGateway myGateway;
private int myChangeSetDepth = 0;
public LocalHistoryEventDispatcher(LocalHistoryFacade vcs, IdeaGateway gw) {
myVcs = vcs;
@@ -64,41 +62,22 @@ public class LocalHistoryEventDispatcher extends VirtualFileAdapter implements V
public void undoTransparentActionFinished() {
}
public synchronized void startAction() {
// save document in current or new changeset and close it
if (myChangeSetDepth == 0) {
myVcs.beginChangeSet();
}
public void startAction() {
myGateway.registerUnsavedDocuments(myVcs);
myVcs.endChangeSet(null);
// restore changeset if there were before saving the documents
if (myChangeSetDepth > 0) {
myVcs.beginChangeSet();
}
beginChangeSet();
myVcs.forceBeginChangeSet();
}
public synchronized void finishAction(String name) {
public void finishAction(String name) {
myGateway.registerUnsavedDocuments(myVcs);
endChangeSet(name);
}
private synchronized void beginChangeSet() {
myChangeSetDepth++;
if (myChangeSetDepth == 1) {
myVcs.beginChangeSet();
}
private void beginChangeSet() {
myVcs.beginChangeSet();
}
private synchronized void endChangeSet(String name) {
LocalHistoryLog.LOG.assertTrue(myChangeSetDepth > 0, "changeset depth is invalid");
myChangeSetDepth--;
if (myChangeSetDepth == 0) {
myVcs.endChangeSet(name);
}
private void endChangeSet(String name) {
myVcs.endChangeSet(name);
}
@Override
@@ -113,7 +92,7 @@ public class LocalHistoryEventDispatcher extends VirtualFileAdapter implements V
myVcs.created(f.getPath(), f.isDirectory());
}
if (f.isDirectory()) {
for (VirtualFile each : ((NewVirtualFile)f).getChildren()) {
for (VirtualFile each : ((NewVirtualFile)f).iterInDbChildren()) {
createRecursively(each);
}
}
@@ -81,7 +81,6 @@ public class DirectoryHistoryDialog extends HistoryDialog<DirectoryHistoryDialog
p.add(myToolBar.getComponent(), BorderLayout.NORTH);
p.add(myChangesTree, BorderLayout.CENTER);
p.add(new DiffStatusBar(DiffStatusBar.DEFAULT_TYPES), BorderLayout.SOUTH);
return p;
}
@@ -115,6 +115,28 @@ public class ChangeListTest extends ChangeListTestCase {
assertEquals(array(c1, c2), cc.get(0).getChanges());
}
@Test
public void testForcesBegin() throws Exception {
facade.beginChangeSet();
add(facade, createFile(r, "f1"));
facade.beginChangeSet();
add(facade, createFile(r, "f2"));
facade.forceBeginChangeSet();
add(facade, createFile(r, "f3"));
facade.endChangeSet("a");
add(facade, createFile(r, "f4"));
facade.endChangeSet("b");
add(facade, createFile(r, "f5"));
facade.endChangeSet("c");
List<ChangeSet> cc = facade.getChangeListInTests().getChangesInTests();
assertEquals(2, cc.size());
assertEquals("c", cc.get(0).getName());
assertEquals(3, cc.get(0).getChanges().size());
assertEquals(null, cc.get(1).getName());
assertEquals(2, cc.get(1).getChanges().size());
}
@Test
public void testChangeSetTimestamp() {
setCurrentTimestamp(123);
@@ -0,0 +1,147 @@
/*
* Copyright 2000-2010 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.historyIntegrTests;
import com.intellij.history.core.LinkedStorage;
import com.intellij.util.io.storage.AbstractStorage;
import java.io.DataInputStream;
import java.io.IOException;
public class LinkedStorageTest extends IntegrationTestCase {
private LinkedStorage myStorage;
@Override
public void setUp() throws Exception {
super.setUp();
myStorage = new LinkedStorage(myRoot.getPath() + "/storage");
}
@Override
protected void tearDown() throws Exception {
myStorage.dispose();
super.tearDown();
}
public void testBasic() throws Exception {
assertFirstAndLast(0, 0);
int r1 = createRecord();
int r2 = createRecord();
assertFirstAndLast(r1, r2);
assertRecord(r2, r1, 0);
assertRecord(r1, 0, r2);
}
public void testDeletion() throws Exception {
int r1 = createRecord();
int r2 = createRecord();
int r3 = createRecord();
assertFirstAndLast(r1, r3);
assertRecord(r3, r2, 0);
assertRecord(r2, r1, r3);
assertRecord(r1, 0, r2);
myStorage.deleteRecord(r2);
assertFirstAndLast(r1, r3);
assertRecord(r3, r1, 0);
assertRecord(r1, 0, r3);
myStorage.deleteRecord(r3);
assertFirstAndLast(r1, r1);
assertRecord(r1, 0, 0);
int r4 = createRecord();
assertFirstAndLast(r1, r4);
assertRecord(r4, r1, 0);
assertRecord(r1, 0, r4);
myStorage.deleteRecord(r1);
assertFirstAndLast(r4, r4);
assertRecord(r4, 0, 0);
myStorage.deleteRecord(r4);
assertFirstAndLast(0, 0);
}
public void testReopening() throws Exception {
int r1 = createRecord();
int r2 = createRecord();
int r3 = createRecord();
myStorage.deleteRecord(r2);
myStorage.dispose();
myStorage = new LinkedStorage(myRoot.getPath() + "/storage");
assertFirstAndLast(r1, r3);
assertRecord(r3, r1, 0);
assertRecord(r1, 0, r3);
myStorage.deleteRecord(r1);
myStorage.dispose();
myStorage = new LinkedStorage(myRoot.getPath() + "/storage");
assertFirstAndLast(r3, r3);
assertRecord(r3, 0, 0);
int r4 = createRecord();
myStorage.dispose();
myStorage = new LinkedStorage(myRoot.getPath() + "/storage");
assertFirstAndLast(r3, r4);
assertRecord(r4, r3, 0);
assertRecord(r3, 0, r4);
}
private int createRecord() throws IOException {
int r = myStorage.createNextRecord();
AbstractStorage.StorageDataOutput s = myStorage.writeStream(r);
for (int i = 0; i < 1000; i++) {
s.writeInt(r);
}
s.close();
return r;
}
private void assertFirstAndLast(int first, int last) {
assertEquals(first, myStorage.getFirstRecord());
assertEquals(last, myStorage.getLastRecord());
}
private void assertRecord(int id, int prev, int next) throws IOException {
assertEquals(prev, myStorage.getPrevRecord(id));
assertEquals(next, myStorage.getNextRecord(id));
DataInputStream s = myStorage.readStream(id);
try {
for (int i = 0; i < 1000; i++) {
assertEquals(id, s.readInt());
}
}
finally {
s.close();
}
}
}
@@ -20,7 +20,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Map;
/**
* @author oleg
* @author Roman.Chernyatchik, oleg
*/
public interface CommandLineArgumentsProvider {
/**
@@ -24,6 +24,7 @@ import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.encoding.EncodingManager;
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
import com.intellij.openapi.vfs.newvfs.events.VFilePropertyChangeEvent;
import com.intellij.util.Icons;
import org.jetbrains.annotations.NonNls;
@@ -36,6 +37,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.List;
/**
* Represents a file in <code>{@link VirtualFileSystem}</code>. A particular file is represented by the same
@@ -451,7 +453,10 @@ public abstract class VirtualFile extends UserDataHolderBase implements Modifica
if (isValid() && !application.isDisposed()) {
application.runWriteAction(new Runnable(){
public void run() {
application.getMessageBus().syncPublisher(VirtualFileManager.VFS_CHANGES).after(Collections.singletonList(new VFilePropertyChangeEvent(this, VirtualFile.this, PROP_ENCODING, old, charset, false)));
List<VFilePropertyChangeEvent> events = Collections.singletonList(new VFilePropertyChangeEvent(this, VirtualFile.this, PROP_ENCODING, old, charset, false));
BulkFileListener listener = application.getMessageBus().syncPublisher(VirtualFileManager.VFS_CHANGES);
listener.before(events);
listener.after(events);
}
});
}
@@ -24,6 +24,7 @@ import com.intellij.openapi.ui.FixedSizeButton;
import com.intellij.openapi.ui.Splitter;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.CharFilter;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
@@ -50,6 +51,11 @@ public class GuiUtils {
private static final Insets paddingInsideDialog = new Insets(5, 5, 5, 5);
public static final int lengthForFileField = 25;
private static final CharFilter NOT_MNEMONIC_CHAR_FILTER = new CharFilter() {
public boolean accept(char ch) {
return ch != '&' && ch != UIUtil.MNEMONIC;
}
};
public static JPanel constructFieldWithBrowseButton(JComponent aComponent, ActionListener aActionListener) {
return constructFieldWithBrowseButton(aComponent, aActionListener, 0);
@@ -187,7 +193,7 @@ public class GuiUtils {
}
public static String getTextWithoutMnemonicEscaping(String text) {
return text.replaceAll("&", "");
return StringUtil.strip(text, NOT_MNEMONIC_CHAR_FILTER);
}
public static char getDisplayedMnemonic(String text) {
@@ -17,14 +17,15 @@ package com.intellij.ide.impl.dataRules;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ex.EditorEx;
public class CopyProviderRule implements GetDataRule {
public Object getData(DataProvider dataProvider) {
final EditorEx editor = (EditorEx)dataProvider.getData(PlatformDataKeys.EDITOR.getName());
if (editor == null) {
return null;
final Editor editor = PlatformDataKeys.EDITOR.getData(dataProvider);
if (editor instanceof EditorEx) {
return ((EditorEx) editor).getCopyProvider();
}
return editor.getCopyProvider();
return null;
}
}
@@ -17,14 +17,15 @@ package com.intellij.ide.impl.dataRules;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ex.EditorEx;
public class CutProviderRule implements GetDataRule {
public Object getData(DataProvider dataProvider) {
final EditorEx editor = (EditorEx)dataProvider.getData(PlatformDataKeys.EDITOR.getName());
if (editor == null) {
return null;
final Editor editor = PlatformDataKeys.EDITOR.getData(dataProvider);
if (editor instanceof EditorEx) {
return ((EditorEx) editor).getCutProvider();
}
return editor.getCutProvider();
return null;
}
}
@@ -17,15 +17,15 @@ package com.intellij.ide.impl.dataRules;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ex.EditorEx;
public class PasteProviderRule implements GetDataRule {
public Object getData(DataProvider dataProvider) {
final EditorEx editor = (EditorEx)dataProvider.getData(PlatformDataKeys.EDITOR.getName());
if (editor == null) {
return null;
final Editor editor = PlatformDataKeys.EDITOR.getData(dataProvider);
if (editor instanceof EditorEx) {
return ((EditorEx) editor).getPasteProvider();
}
return editor.getPasteProvider();
return null;
}
}
@@ -16,7 +16,7 @@
package com.intellij.openapi.editor.colors.impl;
import com.intellij.openapi.extensions.ExtensionPointName;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Roman Chernyatchik
@@ -29,6 +29,9 @@ public interface BundledColorSchemesProvider {
* @return Array of relative paths without extensions for schemes.
* E.g. : ["/colorSchemes/colbalt", "myscheme"] for colorSchemes/colbalt.xml, myscheme.xml
*/
@NotNull
@Nullable
String[] getBundledSchemesRelativePaths();
@Nullable
String getDefaultSchemaExtensionPath();
}
@@ -25,10 +25,9 @@ import com.intellij.openapi.application.ex.DecodeDefaultsUtil;
import com.intellij.openapi.components.ExportableApplicationComponent;
import com.intellij.openapi.components.RoamingType;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.colors.EditorColorsListener;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.colors.*;
import com.intellij.openapi.editor.colors.ex.DefaultColorSchemesManager;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.options.*;
import com.intellij.openapi.util.*;
import org.jdom.Document;
@@ -37,13 +36,11 @@ import org.jdom.JDOMException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.*;
public class EditorColorsManagerImpl extends EditorColorsManager
implements NamedJDOMExternalizable, ExportableApplicationComponent {
@@ -113,38 +110,73 @@ public class EditorColorsManagerImpl extends EditorColorsManager
addDefaultSchemes();
// Change some attributes of default schema using special extension
extendDefaultScheme();
// Load default schemes from providers
loadAdditionalDefaultSchemes();
loadAllSchemes();
setGlobalScheme(myDefaultColorSchemesManager.getAllSchemes()[0]);
}
private void extendDefaultScheme() {
final EditorColorsScheme defaultColorsScheme = mySchemesManager.findSchemeByName("Default");
//Get color scheme from EPs
for (BundledColorSchemesProvider provider : BundledColorSchemesProvider.EP_NAME.getExtensions()) {
final String extensionPath = provider.getDefaultSchemaExtensionPath();
if (extensionPath == null) {
continue;
}
try {
final EditorColorsSchemeImpl extScheme = loadScheme(extensionPath, provider);
if (extScheme != null) {
// copy text attrs from extension to default scheme
for (Map.Entry<TextAttributesKey, TextAttributes> keyTextAttributesEntry : extScheme.myAttributesMap.entrySet()) {
final TextAttributesKey key = keyTextAttributesEntry.getKey();
final TextAttributes attrs = keyTextAttributesEntry.getValue();
((AbstractColorsScheme)defaultColorsScheme).myAttributesMap.put(key, attrs);
}
// copy colors
for (Map.Entry<ColorKey, Color> keyColorEntry : extScheme.myColorsMap.entrySet()) {
final ColorKey key = keyColorEntry.getKey();
final Color color = keyColorEntry.getValue();
((AbstractColorsScheme)defaultColorsScheme).myColorsMap.put(key, color);
}
}
}
catch (final Exception e) {
ApplicationManager.getApplication().invokeLater(
new Runnable(){
public void run() {
// Error shouldn't occur during this operation
// thus we report error instead of info
LOG.error("Cannot read scheme from " + extensionPath + ": " + e.getLocalizedMessage(), e);
}
}
);
}
}
}
private void loadAdditionalDefaultSchemes() {
//Get color schemes from EPs
for (BundledColorSchemesProvider provider : BundledColorSchemesProvider.EP_NAME.getExtensions()) {
final String[] schemesPaths = provider.getBundledSchemesRelativePaths();
if (schemesPaths == null) {
continue;
}
for (final String schemePath : schemesPaths) {
try {
final InputStream inputStream = DecodeDefaultsUtil.getDefaultsInputStream(provider, schemePath);
if (inputStream == null) {
// Error shouldn't occur during this operation
// thus we report error instead of info
LOG.error("Cannot read scheme from " + schemePath);
continue;
final EditorColorsSchemeImpl scheme = loadScheme(schemePath, provider);
if (scheme != null) {
mySchemesManager.addNewScheme(scheme, false);
}
final Document document;
try {
document = JDOMUtil.loadDocument(inputStream);
}
catch (JDOMException e) {
LOG.info("Error reading scheme from " + schemePath + ": " + e.getLocalizedMessage());
throw e;
}
final EditorColorsSchemeImpl scheme = loadSchemeFromDocument(document, false);
mySchemesManager.addNewScheme(scheme, false);
}
catch (final Exception e) {
ApplicationManager.getApplication().invokeLater(
@@ -161,6 +193,28 @@ public class EditorColorsManagerImpl extends EditorColorsManager
}
}
private EditorColorsSchemeImpl loadScheme(@NotNull final String schemePath,
final BundledColorSchemesProvider provider)
throws IOException, JDOMException, InvalidDataException {
final InputStream inputStream = DecodeDefaultsUtil.getDefaultsInputStream(provider, schemePath);
if (inputStream == null) {
// Error shouldn't occur during this operation
// thus we report error instead of info
LOG.error("Cannot read scheme from " + schemePath);
return null;
}
final Document document;
try {
document = JDOMUtil.loadDocument(inputStream);
}
catch (JDOMException e) {
LOG.info("Error reading scheme from " + schemePath + ": " + e.getLocalizedMessage());
throw e;
}
return loadSchemeFromDocument(document, false);
}
private EditorColorsSchemeImpl loadSchemeFromDocument(final Document document,
final boolean isEditable)
throws InvalidDataException {
@@ -108,7 +108,6 @@ public class ColorProgressBar extends JComponent {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (myFraction == 0) return;
Graphics2D g2 = (Graphics2D)g;
Object oldAntialiasing = g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
@@ -110,6 +110,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
connection.subscribe(StateStorage.STORAGE_TOPIC, new StateStorage.Listener() {
public void storageFileChanged(final VirtualFileEvent event, @NotNull final StateStorage storage) {
VirtualFile file = event.getFile();
LOG.info("[RELOAD] Storage file changed: " + file.getPath());
if (!file.isDirectory() && !(event.getRequestor() instanceof StateStorage.SaveSession)) {
saveChangedProjectFile(file, null, storage);
}
@@ -535,6 +536,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
}
private void askToReloadProjectIfConfigFilesChangedExternally() {
LOG.info("[RELOAD] myReloadBlockCount = " + myReloadBlockCount.get());
if (myReloadBlockCount.get() == 0) {
Set<Project> projects;
@@ -572,7 +574,6 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
try {
reloadOk[0] = ((ApplicationImpl)app).getStateStore().reload(causes, components);
}
catch (StateStorage.StateStorageException e) {
@@ -639,6 +640,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
try {
LOG.info("[RELOAD] Reloading project/components...");
reloadOk[0] = ((ProjectEx)project).getStateStore().reload(causes);
}
catch (StateStorage.StateStorageException e) {
@@ -725,6 +727,8 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
}
private void registerProjectToReload(final Project project, final VirtualFile cause, final StateStorage storage) {
LOG.info("[RELOAD] Registering project to reload.");
if (project != null) {
synchronized (myChangedProjectFiles) {
List<Pair<VirtualFile, StateStorage>> changedProjectFiles = myChangedProjectFiles.get(project);
@@ -743,6 +747,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
myChangedFilesAlarm.cancelAllRequests();
myChangedFilesAlarm.addRequest(new Runnable() {
public void run() {
LOG.info("[RELOAD] Scheduling reload application & project, myReloadBlockCount = " + myReloadBlockCount);
if (myReloadBlockCount.get() == 0) {
scheduleReloadApplicationAndProject();
}
@@ -22,19 +22,13 @@
<keyboard-shortcut first-keystroke="shift alt C" />
</action>
<action id="CheckinProject" />
<action id="CloseActiveTab">
<keyboard-shortcut first-keystroke="control F4" />
<keyboard-shortcut first-keystroke="control W" />
</action>
<action id="CloseActiveTab" />
<action id="CloseAllEditors">
<keyboard-shortcut first-keystroke="shift control F4" />
<keyboard-shortcut first-keystroke="shift control W" />
</action>
<action id="CloseEditor" />
<action id="CloseWindow">
<keyboard-shortcut first-keystroke="control F4" />
<keyboard-shortcut first-keystroke="control W" />
</action>
<action id="CloseWindow" />
<action id="CodeInspection.OnEditor" />
<action id="CollapseAllRegions">
<keyboard-shortcut first-keystroke="shift control DIVIDE" />
@@ -224,7 +224,7 @@
<keyboard-shortcut first-keystroke="UP"/>
<keyboard-shortcut first-keystroke="control P"/>
</action>
<action id="CloseEditor">
<action id="CloseContent">
<keyboard-shortcut first-keystroke="control F4"/>
<keyboard-shortcut first-keystroke="control X" second-keystroke="K"/>
</action>
@@ -6,7 +6,7 @@
<action id="CloseActiveTab">
<keyboard-shortcut first-keystroke="shift control 4" />
</action>
<action id="CloseEditor">
<action id="CloseContent">
<keyboard-shortcut first-keystroke="control 4" />
</action>
<action id="CompileDirty">
@@ -42,20 +42,16 @@
<keyboard-shortcut first-keystroke="control alt BACK_SLASH" />
</action>
<action id="CloneElement" />
<action id="CloseActiveTab">
<keyboard-shortcut first-keystroke="control W" />
</action>
<action id="CloseActiveTab" />
<action id="CloseAllEditors">
<keyboard-shortcut first-keystroke="shift control W" />
<keyboard-shortcut first-keystroke="shift control F4" />
</action>
<action id="CloseEditor">
<action id="CloseContent">
<keyboard-shortcut first-keystroke="control F4" />
<keyboard-shortcut first-keystroke="control W" />
</action>
<action id="CloseWindow">
<keyboard-shortcut first-keystroke="control W" />
</action>
<action id="CloseWindow" />
<action id="CodeCompletion">
<keyboard-shortcut first-keystroke="control SPACE" />
<keyboard-shortcut first-keystroke="control BACK_SLASH" />
@@ -173,9 +173,12 @@ public abstract class AbstractRecordsTable implements Disposable, Forceable {
public void deleteRecord(final int record) {
ensureFreeRecordsScanned();
setSize(record, -1);
clearDeletedRecord(record);
myFreeRecordsList.add(record);
}
protected abstract void clearDeletedRecord(int record);
public int getVersion() {
return myStorage.getInt(HEADER_VERSION_OFFSET);
}
@@ -47,4 +47,8 @@ class RecordsTable extends AbstractRecordsTable {
protected byte[] getZeros() {
return ZEROES;
}
@Override
protected void clearDeletedRecord(int record) {
}
}
@@ -47,6 +47,11 @@ class RefCountingRecordsTable extends AbstractRecordsTable {
return ZEROES;
}
@Override
protected void clearDeletedRecord(int record) {
myStorage.putInt(getOffset(record, REF_COUNT_OFFSET), 0);
}
public void incRefCount(int record) {
markDirty();
@@ -0,0 +1,35 @@
/*
* Copyright 2000-2010 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.xdebugger.frame;
import org.jetbrains.annotations.NotNull;
/**
* @author nik
*/
public class ImmediateFullValueEvaluator extends XFullValueEvaluator {
private String myFullValue;
public ImmediateFullValueEvaluator(@NotNull String linkText, @NotNull String fullValue) {
super(linkText);
myFullValue = fullValue;
}
@Override
public void startEvaluation(@NotNull XFullValueEvaluationCallback callback) {
callback.evaluated(myFullValue);
}
}
@@ -0,0 +1,52 @@
/*
* Copyright 2000-2010 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.xdebugger.frame;
import org.jetbrains.annotations.NotNull;
/**
* Supports asynchronous fetching full text of a value. If full text is already computed use {@link ImmediateFullValueEvaluator}
* @see XValueNode#setFullValueEvaluator
* @see ImmediateFullValueEvaluator
*
* @author nik
*/
public abstract class XFullValueEvaluator {
private String myLinkText;
/**
* @param linkText text of the link what will be appended to a variables tree node text
*/
protected XFullValueEvaluator(@NotNull String linkText) {
myLinkText = linkText;
}
/**
* Start fetching full text of the value. Note that this method is called from the Event Dispatch Thread so it should return quickly
* @param callback used to notify that the full text has been successfully evaluated or an error occurs
*/
public abstract void startEvaluation(@NotNull XFullValueEvaluationCallback callback);
public String getLinkText() {
return myLinkText;
}
public interface XFullValueEvaluationCallback {
void evaluated(@NotNull String fullValue);
void errorOccurred(@NotNull String errorMessage);
}
}
@@ -24,7 +24,7 @@ import org.jetbrains.annotations.Nullable;
public abstract class XValueModifier {
/**
* Start modification of the value. Note that this methods is called from the Event Dispatch Thread so it should return quickly
* Start modification of the value. Note that this method is called from the Event Dispatch Thread so it should return quickly
* @param expression new value
* @param callback used to notify that value has been successfully modified or an error occurs
*/
@@ -38,9 +38,8 @@ public interface XValueNode extends Obsolescent {
/**
* If string representation of the value is too long to show in the tree pass truncated value to {@link #setPresentation(String, javax.swing.Icon, String, String, boolean)}
* method and call this method to provide full value.
* This will add a link to the node and show <code>fullValue</code> text if a user click on that link.
* @param fullValue full text of the value. Will be shown in popup window
* @param linkText text of the link. Will be appended to the node text
* This will add a link to the node and show popup with full value if an user clicks on that link.
* @param fullValueEvaluator will be used to obtain full text of the value
*/
void setFullValue(@NotNull String fullValue, @NotNull String linkText);
void setFullValueEvaluator(@NotNull XFullValueEvaluator fullValueEvaluator);
}
@@ -30,6 +30,7 @@ import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XDebuggerUtil;
import com.intellij.xdebugger.XSourcePosition;
import com.intellij.xdebugger.evaluation.XDebuggerEvaluator;
import com.intellij.xdebugger.frame.XFullValueEvaluator;
import com.intellij.xdebugger.frame.XValue;
import com.intellij.xdebugger.frame.XValueNode;
import com.intellij.xdebugger.impl.evaluate.quick.common.AbstractValueHint;
@@ -90,7 +91,7 @@ public class XValueHint extends AbstractValueHint {
});
}
public void setFullValue(@NotNull String fullValue, @NotNull String linkText) {
public void setFullValueEvaluator(@NotNull XFullValueEvaluator fullValueEvaluator) {
//todo[nik] implement?
}
@@ -25,6 +25,7 @@ import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.xdebugger.frame.XFullValueEvaluator;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
@@ -90,26 +91,52 @@ public class DebuggerUIUtil {
return new RelativePoint(editor.getContentComponent(), p);
}
public static void showValuePopup(@NotNull String text, @NotNull MouseEvent event, @NotNull Project project) {
JTextArea textArea = new JTextArea(text);
public static void showValuePopup(@NotNull XFullValueEvaluator text, @NotNull MouseEvent event, @NotNull Project project) {
final JTextArea textArea = new JTextArea("Evaluating...");
text.startEvaluation(new FullValueEvaluationCallbackImpl(textArea));
textArea.setEditable(false);
textArea.setBackground(HintUtil.INFORMATION_COLOR);
textArea.setLineWrap(false);
final JScrollPane component = ScrollPaneFactory.createScrollPane(textArea);
final Dimension frameSize = WindowManager.getInstance().getFrame(project).getSize();
final Dimension size = new Dimension(frameSize.width / 2, frameSize.height / 2);
component.setPreferredSize(size);
component.setBorder(null);
final JBPopup popup = JBPopupFactory.getInstance().createComponentPopupBuilder(component, null)
.setResizable(true)
.setMovable(true)
.setDimensionServiceKey(project, "XDebugger.FullValuePopup", false)
.setRequestFocus(false)
.createPopup();
final Dimension size = textArea.getPreferredSize();
final Component parentComponent = event.getComponent();
final Dimension frameSize = WindowManager.getInstance().getFrame(project).getSize();
size.width = Math.min(size.width, frameSize.width / 2);
size.height = Math.min(size.height, frameSize.height / 2);
component.setPreferredSize(size);
RelativePoint point = new RelativePoint(parentComponent, new Point(event.getX()-size.width, event.getY()-size.height));
popup.show(point);
}
private static class FullValueEvaluationCallbackImpl implements XFullValueEvaluator.XFullValueEvaluationCallback {
private final JTextArea myTextArea;
public FullValueEvaluationCallbackImpl(JTextArea textArea) {
myTextArea = textArea;
}
public void evaluated(@NotNull final String fullValue) {
invokeOnEventDispatch(new Runnable() {
public void run() {
myTextArea.setText(fullValue);
myTextArea.setCaretPosition(0);
}
});
}
public void errorOccurred(@NotNull final String errorMessage) {
invokeOnEventDispatch(new Runnable() {
public void run() {
myTextArea.setForeground(XDebuggerUIConstants.ERROR_MESSAGE_ATTRIBUTES.getFgColor());
myTextArea.setText(errorMessage);
}
});
}
}
}
@@ -20,6 +20,7 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.StringBuilderSpinAllocator;
import com.intellij.xdebugger.frame.XCompositeNode;
import com.intellij.xdebugger.frame.XFullValueEvaluator;
import com.intellij.xdebugger.frame.XValue;
import com.intellij.xdebugger.frame.XValueNode;
import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
@@ -39,10 +40,9 @@ public class XValueNodeImpl extends XValueContainerNode<XValue> implements XValu
private String myName;
private String myType;
private String myValue;
private String myFullValue;
private XFullValueEvaluator myFullValueEvaluator;
private String mySeparator;
private boolean myChanged;
private String myLinkText;
public XValueNodeImpl(XDebuggerTree tree, final XDebuggerTreeNode parent, final XValue value) {
super(tree, parent, value);
@@ -74,11 +74,10 @@ public class XValueNodeImpl extends XValueContainerNode<XValue> implements XValu
});
}
public void setFullValue(@NotNull final String fullValue, @NotNull final String linkText) {
public void setFullValueEvaluator(@NotNull final XFullValueEvaluator fullValueEvaluator) {
DebuggerUIUtil.invokeOnEventDispatch(new Runnable() {
public void run() {
myLinkText = linkText;
myFullValue = fullValue;
myFullValueEvaluator = fullValueEvaluator;
fireNodeChanged();
}
});
@@ -122,11 +121,11 @@ public class XValueNodeImpl extends XValueContainerNode<XValue> implements XValu
@Override
public XDebuggerNodeLink getLink() {
if (myFullValue != null) {
return new XDebuggerNodeLink(myLinkText) {
if (myFullValueEvaluator != null) {
return new XDebuggerNodeLink(myFullValueEvaluator.getLinkText()) {
@Override
public void onClick(MouseEvent event) {
DebuggerUIUtil.showValuePopup(myFullValue, event, myTree.getProject());
DebuggerUIUtil.showValuePopup(myFullValueEvaluator, event, myTree.getProject());
}
};
}
@@ -135,9 +134,6 @@ public class XValueNodeImpl extends XValueContainerNode<XValue> implements XValu
@Nullable
public String getValue() {
if (myFullValue != null) {
return myFullValue;
}
return myValue;
}
@@ -71,7 +71,7 @@ public class GenerateToStringUtils {
List<PsiField> availableFields = new ArrayList<PsiField>();
// performs til filtering process
PsiField[] fields = psi.getFields(clazz);
PsiField[] fields = clazz.getFields();
for (PsiField field : fields) {
FieldElement fe = ElementFactory.newFieldElement(project, field, psi);
if (log.isDebugEnabled()) log.debug("Field being filtered: " + fe);
@@ -103,7 +103,7 @@ public class GenerateToStringUtils {
List<PsiMethod> availableMethods = new ArrayList<PsiMethod>();
PsiElementFactory elementFactory = JavaPsiFacade.getInstance(clazz.getProject()).getElementFactory();
PsiMethod[] methods = psi.getMethods(clazz);
PsiMethod[] methods = clazz.getMethods();
for (PsiMethod method : methods) {
MethodElement me = ElementFactory.newMethodElement(method, elementFactory, psi);
@@ -65,7 +65,7 @@ public class GenerateToStringWorker {
this.psi = PsiAdapterFactory.getPsiAdapter();
this.editor = editor;
this.elementFactory = JavaPsiFacade.getInstance(project).getElementFactory();
this.codeStyleManager = psi.getCodeStyleManager(project);
this.codeStyleManager = CodeStyleManager.getInstance(project);
this.containingFile = clazz.getContainingFile();
this.config = GenerateToStringContext.getConfig();
this.hasOverrideAnnotation = insertAtOverride;
@@ -55,9 +55,9 @@ public class ElementFactory {
ce.setImplementNames(psi.getImplementsClassnames(clazz));
// other
ce.setEnum(psi.isEnumClass(clazz));
ce.setDeprecated(psi.isDeprecatedClass(clazz));
ce.setException(psi.isExceptionClass(clazz));
ce.setEnum(clazz.isEnum());
ce.setDeprecated(clazz.isDeprecated());
ce.setException(PsiAdapter.isExceptionClass(clazz));
ce.setAbstract(psi.isAbstractClass(clazz));
return ce;
@@ -83,8 +83,8 @@ public class ElementFactory {
if (psi.isEnumField(field)) fe.setEnum(true);
PsiModifierList modifiers = field.getModifierList();
if (modifiers != null) {
if (psi.isModifierTransient(modifiers)) fe.setModifierTransient(true);
if (psi.isModifierVolatile(modifiers)) fe.setModifierVolatile(true);
if (modifiers.hasModifierProperty(PsiModifier.TRANSIENT)) fe.setModifierTransient(true);
if (modifiers.hasModifierProperty(PsiModifier.VOLATILE)) fe.setModifierVolatile(true);
}
setElementInfo(fe, factory, type, modifiers, psi);
@@ -126,11 +126,11 @@ public class ElementFactory {
// misc
me.setReturnTypeVoid(psi.isTypeOfVoid(method.getReturnType()));
me.setDeprecated(psi.isDeprecatedMethod(method));
me.setDeprecated(method.isDeprecated());
// modifiers
if (psi.isModifierAbstract(modifiers)) me.setModifierAbstract(true);
if (psi.isModifierSynchronized(modifiers)) me.setModifierSynchronzied(true);
if (modifiers.hasModifierProperty(PsiModifier.ABSTRACT)) me.setModifierAbstract(true);
if (modifiers.hasModifierProperty(PsiModifier.SYNCHRONIZED)) me.setModifierSynchronzied(true);
return me;
}
@@ -184,18 +184,18 @@ public class ElementFactory {
// modifiers
if (modifiers != null) {
if (psi.isModifierStatic(modifiers)) element.setModifierStatic(true);
if (psi.isModifierFinal(modifiers)) element.setModifierFinal(true);
if (psi.isModifierPublic(modifiers)) {
if (modifiers.hasModifierProperty(PsiModifier.STATIC)) element.setModifierStatic(true);
if (modifiers.hasModifierProperty(PsiModifier.FINAL)) element.setModifierFinal(true);
if (modifiers.hasModifierProperty(PsiModifier.PUBLIC)) {
element.setModifierPublic(true);
}
else if (psi.isModifierProtected(modifiers)) {
else if (modifiers.hasModifierProperty(PsiModifier.PROTECTED)) {
element.setModifierProtected(true);
}
else if (psi.isModifierPackageLocal(modifiers)) {
else if (modifiers.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) {
element.setModifierPackageLocal(true);
}
else if (psi.isModifierPrivate(modifiers)) element.setModifierPrivate(true);
else if (modifiers.hasModifierProperty(PsiModifier.PRIVATE)) element.setModifierPrivate(true);
}
}
@@ -85,19 +85,19 @@ public class ClassHasNoToStringMethodInspection extends AbstractToStringInspecti
PsiAdapter psi = PsiAdapterFactory.getPsiAdapter();
// must not be an exception
if (excludeException && psi.isExceptionClass(clazz)) {
if (excludeException && PsiAdapter.isExceptionClass(clazz)) {
log.debug("This class is an exception");
return;
}
// must not be deprecated
if (excludeDeprecated && psi.isDeprecatedClass(clazz)) {
if (excludeDeprecated && clazz.isDeprecated()) {
log.debug("Class is deprecated");
return;
}
// must not be enum
if (excludeEnum && psi.isEnumClass(clazz)) {
if (excludeEnum && clazz.isEnum()) {
log.debug("Class is an enum");
return;
}
@@ -117,7 +117,7 @@ public class ClassHasNoToStringMethodInspection extends AbstractToStringInspecti
}
// must have fields
PsiField[] fields = psi.getFields(clazz);
PsiField[] fields = clazz.getFields();
if (fields.length == 0) {
log.debug("Class does not have any fields");
return;
@@ -83,7 +83,7 @@ public class FieldNotUsedInToStringInspection extends AbstractToStringInspection
// must have fields
PsiAdapter psi = PsiAdapterFactory.getPsiAdapter();
PsiField[] fields = psi.getFields(clazz);
PsiField[] fields = clazz.getFields();
if (fields.length == 0) {
log.debug("Class does not have any fields");
return;
@@ -181,7 +181,7 @@ public class FieldNotUsedInToStringInspection extends AbstractToStringInspection
}
// must have methods
PsiMethod[] methods = psi.getMethods(clazz);
PsiMethod[] methods = clazz.getMethods();
if (methods.length == 0) {
log.debug("Class does not have any methods");
return;
@@ -22,6 +22,7 @@ import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.Nullable;
@@ -39,16 +40,6 @@ public abstract class PsiAdapter {
}
/**
* Get's the fields for the class.
*
* @param clazz class.
* @return the fields for the class. If the class doesn't have any fields the array's size is 0.
*/
public PsiField[] getFields(PsiClass clazz) {
return clazz.getFields();
}
/**
* Finds the class for the given element.
* <p/>
* Will look in the element's parent hieracy.
@@ -271,116 +262,6 @@ public abstract class PsiAdapter {
}
}
/**
* Is there a <code>transient</code> modifier?
* <p/>eg: <code>private transient String myField;</code>.
*
* @param modifiers the modifiers
*/
public boolean isModifierTransient(PsiModifierList modifiers) {
return modifiers.hasModifierProperty(PsiModifier.TRANSIENT);
}
/**
* Is there a <code>volatile</code> modifier?
* <p/>eg: <code>private volatile Image screen;</code>.
*
* @param modifiers the modifiers
*/
public boolean isModifierVolatile(PsiModifierList modifiers) {
return modifiers.hasModifierProperty(PsiModifier.VOLATILE);
}
/**
* Is there a <code>public</code> modifier?
* <p/>eg: <code>public String myField;</code>.
*
* @param modifiers the modifiers
*/
public boolean isModifierPublic(PsiModifierList modifiers) {
return modifiers.hasModifierProperty(PsiModifier.PUBLIC);
}
/**
* Is there a <code>protected</code> modifier?
* <p/>eg: <code>public String myField;</code>.
*
* @param modifiers the modifiers
*/
public boolean isModifierProtected(PsiModifierList modifiers) {
return modifiers.hasModifierProperty(PsiModifier.PROTECTED);
}
/**
* Is there a <code>package-local</code> modifier?
* <p/>eg: <code>String myField;</code>.
*
* @param modifiers the modifiers
*/
public boolean isModifierPackageLocal(PsiModifierList modifiers) {
return modifiers.hasModifierProperty(PsiModifier.PACKAGE_LOCAL);
}
/**
* Is there a <code>private</code> modifier?
* <p/>eg: <code>private static String myField;</code>.
*
* @param modifiers the modifiers
*/
public boolean isModifierPrivate(PsiModifierList modifiers) {
return modifiers.hasModifierProperty(PsiModifier.PRIVATE);
}
/**
* Is there a <code>abstract</code> modifier?
* <p/>eg: <code>public abstract String getConfiguration()</code>.
*
* @param modifiers the modifiers
*/
public boolean isModifierAbstract(PsiModifierList modifiers) {
return modifiers.hasModifierProperty(PsiModifier.ABSTRACT);
}
/**
* Is there a <code>final</code> modifier?
* <p/>eg: <code>final static boolean DEBUG = false;</code>.
*
* @param modifiers the modifiers
*/
public boolean isModifierFinal(PsiModifierList modifiers) {
return modifiers.hasModifierProperty(PsiModifier.FINAL);
}
/**
* Is there a <code>static</code> modifier?
* <p/>eg: <code>private static String getMyField()</code>.
*
* @param modifiers the modifiers
*/
public boolean isModifierStatic(PsiModifierList modifiers) {
return modifiers.hasModifierProperty(PsiModifier.STATIC);
}
/**
* Is there a <code>synchronized</code> modifier?
* <p/>eg: <code>public synchronized void putInCache()</code>.
*
* @param modifiers the modifiers
*/
public boolean isModifierSynchronized(PsiModifierList modifiers) {
return modifiers.hasModifierProperty(PsiModifier.SYNCHRONIZED);
}
/**
* Get's the CodeStyleManager for the project.
*
* @param project project.
* @return the CodeStyleManager.
*/
public CodeStyleManager getCodeStyleManager(Project project) {
return CodeStyleManager.getInstance(project);
}
/**
* Does the javafile have the import statement?
*
@@ -592,17 +473,7 @@ public abstract class PsiAdapter {
}
}
/**
* Get's the methods for the class.
*
* @param clazz class.
* @return the methods for the class. If the class doesn't have any methods the array's size is 0.
*/
public PsiMethod[] getMethods(PsiClass clazz) {
return clazz.getMethods();
}
/**
/**
* Find's an existing field with the given name.
* If there isn't a field with the name, null is returned.
*
@@ -725,38 +596,8 @@ public abstract class PsiAdapter {
return false;
}
return isEnumClass(clazz);
}
/**
* Returns true if the class is enum (JDK1.5).
*
* @param clazz class to check if it's a enum
* @return true if enum.
*/
public boolean isEnumClass(PsiClass clazz) {
return clazz.isEnum();
}
/**
* Returns true if the class is deprecated.
*
* @param clazz class to check if it's deprecated
* @return true if deprecated.
*/
public boolean isDeprecatedClass(PsiClass clazz) {
return clazz.isDeprecated();
}
/**
* Returns true if the method is deprecated.
*
* @param method method to check if it's deprecated
* @return true if deprecated.
*/
public boolean isDeprecatedMethod(PsiMethod method) {
return method.isDeprecated();
}
}
/**
* Is the class an exception - extends Throwable (will check super).
@@ -764,17 +605,8 @@ public abstract class PsiAdapter {
* @param clazz class to check.
* @return true if class is an exception.
*/
public boolean isExceptionClass(PsiClass clazz) {
PsiClass[] supers = clazz.getSupers();
for (PsiClass sup : supers) {
if ("java.lang.Throwable".equals(sup.getQualifiedName())) {
return true;
} else if (isExceptionClass(sup)) {
return true;
}
}
return false;
public static boolean isExceptionClass(PsiClass clazz) {
return InheritanceUtil.isInheritor(clazz, CommonClassNames.JAVA_LANG_THROWABLE);
}
/**
@@ -788,7 +620,7 @@ public abstract class PsiAdapter {
if (list == null) {
return false;
}
return isModifierAbstract(clazz.getModifierList());
return clazz.getModifierList().hasModifierProperty(PsiModifier.ABSTRACT);
}
/**
@@ -1,9 +1,9 @@
def <error descr="foo(String, int) already defined">foo</error>(String s = "a", int i, double y = 4) {
def <error descr="foo(String, int) is already defined">foo</error>(String s = "a", int i, double y = 4) {
}
def foo(int i, double y) {}
def <error descr="foo(String, int) already defined">foo</error>(String s, int i) {}
def <error descr="foo(String, int) is already defined">foo</error>(String s, int i) {}
def foo(String s, double y){}
@@ -88,7 +88,7 @@ public class SpellCheckingInspection extends LocalInspectionTool {
private static final Map<Language, SpellcheckingStrategy> factories = new HashMap<Language, SpellcheckingStrategy>();
private static void ensureFactoriesAreLoaded() {
public static void ensureFactoriesAreLoaded() {
synchronized (factories) {
if (!factories.isEmpty()) return;
final SpellcheckingStrategy[] spellcheckingStrategies = Extensions.getExtensions(SpellcheckingStrategy.EP_NAME);
@@ -146,11 +146,8 @@ public class SpellCheckingInspection extends LocalInspectionTool {
}
}
final SpellcheckingStrategy factoryByLanguage = getFactoryByLanguage(language);
final Tokenizer tokenizer = factoryByLanguage.getTokenizer(element);
@SuppressWarnings({"unchecked"})
final Token[] tokens = tokenizer.tokenize(element);
final Token[] tokens = tokenize(element, language);
if (tokens == null) return;
Set<String> alreadyChecked = new THashSet<String>();
@@ -161,6 +158,19 @@ public class SpellCheckingInspection extends LocalInspectionTool {
};
}
/**
* Splits element text in tokens according to spell checker strategy of given language
* @param element Psi element
* @param language Usually element.getLanguage()
* @return tokens array
*/
@Nullable
public static Token[] tokenize(@NotNull final PsiElement element, @NotNull final Language language) {
final SpellcheckingStrategy factoryByLanguage = getFactoryByLanguage(language);
final Tokenizer tokenizer = factoryByLanguage.getTokenizer(element);
return tokenizer.tokenize(element);
}
private static void inspect(Token token, ProblemsHolder holder, boolean isOnTheFly,@NotNull Set<String> alreadyChecked, @NotNull SpellCheckerManager manager, NamesValidator... validators) {
List<CheckArea> areaList = token.getAreas();
@@ -253,7 +263,7 @@ public class SpellCheckingInspection extends LocalInspectionTool {
return validators;
}
private static boolean isKeyword(NamesValidator[] validators, PsiElement element, String word) {
public static boolean isKeyword(NamesValidator[] validators, PsiElement element, String word) {
if (validators == null) {
return false;
}
@@ -1,3 +1,4 @@
rubymine
noinspection
noinspections
impl
@@ -106,4 +107,5 @@ utf
stylesheet
charset
vertices
commandline
cmdline
@@ -553,7 +553,7 @@ public class TestNGUtil implements TestFramework
}
public static boolean isTestngXML(final VirtualFile virtualFile) {
if (virtualFile.getName().endsWith("xml")) {
if ("xml".equalsIgnoreCase(virtualFile.getExtension())) {
final String result = NanoXmlUtil.parseHeader(virtualFile).getRootTagLocalName();
if (result != null && result.equals(SUITE_TAG_NAME)) {
return true;
@@ -48,6 +48,7 @@ import com.intellij.uiDesigner.lw.IComponent;
import com.intellij.uiDesigner.lw.IProperty;
import com.intellij.uiDesigner.lw.LwRootContainer;
import com.intellij.uiDesigner.palette.ComponentItem;
import com.intellij.uiDesigner.propertyInspector.PropertyInspector;
import com.intellij.uiDesigner.propertyInspector.UIDesignerToolWindowManager;
import com.intellij.uiDesigner.propertyInspector.properties.IntroStringProperty;
import com.intellij.uiDesigner.radComponents.RadComponent;
@@ -465,7 +466,8 @@ public final class GuiEditor extends JPanel implements DataProvider {
// Standard Swing cut/copy/paste actions should work if user is editing something inside property inspector
final UIDesignerToolWindowManager manager = UIDesignerToolWindowManager.getInstance(getProject());
if (manager.getPropertyInspector().isEditing()) {
final PropertyInspector inspector = manager.getPropertyInspector();
if (inspector != null && inspector.isEditing()) {
return null;
}
@@ -16,19 +16,20 @@
package com.intellij.uiDesigner.designSurface;
import com.intellij.openapi.util.IconLoader;
import com.intellij.uiDesigner.radComponents.RadRootContainer;
import com.intellij.uiDesigner.FormEditingUtil;
import com.intellij.uiDesigner.propertyInspector.UIDesignerToolWindowManager;
import com.intellij.uiDesigner.componentTree.ComponentTree;
import com.intellij.uiDesigner.propertyInspector.UIDesignerToolWindowManager;
import com.intellij.uiDesigner.radComponents.RadButtonGroup;
import com.intellij.uiDesigner.radComponents.RadComponent;
import com.intellij.uiDesigner.radComponents.RadRootContainer;
import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.util.Set;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
/**
* Decoration layer is over COMPONENT_LAYER (layer where all components are located).
@@ -56,7 +57,9 @@ class PassiveDecorationLayer extends JComponent{
final Set<RadButtonGroup> paintedGroups = new HashSet<RadButtonGroup>();
final RadRootContainer rootContainer = myEditor.getRootContainer();
final ComponentTree componentTree = UIDesignerToolWindowManager.getInstance(component.getProject()).getComponentTree();
final Collection<RadButtonGroup> selectedGroups = componentTree.getSelectedElements(RadButtonGroup.class);
final Collection<RadButtonGroup> selectedGroups = componentTree != null
? componentTree.getSelectedElements(RadButtonGroup.class)
: Collections.<RadButtonGroup>emptyList();
// Paint selection and dragger
FormEditingUtil.iterate(
@@ -121,8 +121,8 @@ class XmlZenCodingInterpreter {
case OPERATION:
if (templateToken != null) {
if (token instanceof MarkerToken || token instanceof OperationToken) {
final char sign = token instanceof OperationToken ? ((OperationToken)token).mySign : XmlZenCodingTemplate.MARKER;
if (sign == '+' || (mySurroundedText == null && sign == XmlZenCodingTemplate.MARKER)) {
final char sign = token instanceof OperationToken ? ((OperationToken)token).mySign : ZenCodingTemplate.MARKER;
if (sign == '+' || (mySurroundedText == null && sign == ZenCodingTemplate.MARKER)) {
final Object key = new Object();
myCallback.fixStartOfTemplate(key);
invokeTemplate(templateToken, myCallback, 0);
@@ -135,7 +135,7 @@ class XmlZenCodingInterpreter {
}
templateToken = null;
}
else if (sign == '>' || (mySurroundedText != null && sign == XmlZenCodingTemplate.MARKER)) {
else if (sign == '>' || (mySurroundedText != null && sign == ZenCodingTemplate.MARKER)) {
startTemplateAndGotoChild(templateToken);
templateToken = null;
}
@@ -168,8 +168,8 @@ class XmlZenCodingInterpreter {
break;
case AFTER_NUMBER:
if (token instanceof MarkerToken || token instanceof OperationToken) {
char sign = token instanceof OperationToken ? ((OperationToken)token).mySign : XmlZenCodingTemplate.MARKER;
if (sign == '+' || (mySurroundedText == null && sign == XmlZenCodingTemplate.MARKER)) {
char sign = token instanceof OperationToken ? ((OperationToken)token).mySign : ZenCodingTemplate.MARKER;
if (sign == '+' || (mySurroundedText == null && sign == ZenCodingTemplate.MARKER)) {
invokeTemplateSeveralTimes(templateToken, 0, number);
templateToken = null;
}
@@ -15,60 +15,38 @@
*/
package com.intellij.codeInsight.template.zencoding;
import com.intellij.application.options.editor.WebEditorOptions;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.template.CustomLiveTemplate;
import com.intellij.codeInsight.template.CustomTemplateCallback;
import com.intellij.codeInsight.template.TemplateInvokationListener;
import com.intellij.codeInsight.template.impl.TemplateImpl;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.lang.xml.XMLLanguage;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorModificationUtil;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.ui.InputValidatorEx;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileFactory;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.*;
import com.intellij.util.LocalTimeCounter;
import com.intellij.util.containers.HashSet;
import com.intellij.xml.XmlBundle;
import org.apache.xerces.util.XML11Char;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
/**
* @author Eugene.Kudelevsky
*/
public class XmlZenCodingTemplate implements CustomLiveTemplate {
static final char MARKER = '$';
private static final String OPERATIONS = ">+*";
public class XmlZenCodingTemplate extends ZenCodingTemplate {
private static final String SELECTORS = ".#[";
private static final String ID = "id";
private static final String CLASS = "class";
private static int parseNonNegativeInt(@NotNull String s) {
try {
return Integer.parseInt(s);
}
catch (Throwable ignored) {
}
return -1;
}
private static final String DEFAULT_TAG = "div";
private static String getPrefix(@NotNull String templateKey) {
for (int i = 0, n = templateKey.length(); i < n; i++) {
@@ -183,187 +161,59 @@ public class XmlZenCodingTemplate implements CustomLiveTemplate {
return type == StdFileTypes.XHTML || type == StdFileTypes.JSPX || type == StdFileTypes.XML;
}
private static boolean isHtml(CustomTemplateCallback callback) {
FileType type = callback.getFileType();
return type == StdFileTypes.HTML || type == StdFileTypes.XHTML;
}
@Override
@Nullable
private static List<Token> parse(@NotNull String text, @NotNull CustomTemplateCallback callback) {
text += MARKER;
StringBuilder templateKeyBuilder = new StringBuilder();
List<Token> result = new ArrayList<Token>();
for (int i = 0, n = text.length(); i < n; i++) {
char c = text.charAt(i);
if (i == n - 1 || (i < n - 2 && OPERATIONS.indexOf(c) >= 0)) {
String key = templateKeyBuilder.toString();
templateKeyBuilder = new StringBuilder();
int num = parseNonNegativeInt(key);
if (num > 0) {
result.add(new NumberToken(num));
}
else {
if (key.length() == 0) {
return null;
}
String prefix = getPrefix(key);
TemplateImpl template = callback.findApplicableTemplate(prefix);
if (template == null && !isXML11ValidQName(prefix)) {
return null;
}
TemplateToken token = parseSelectors(key);
if (token == null) {
return null;
}
if (template != null && (token.myAttribute2Value.size() > 0 || isTrueXml(callback))) {
assert prefix.equals(token.myKey);
token.myTemplate = template;
if (token.myAttribute2Value.size() > 0) {
XmlTag tag = parseXmlTagInTemplate(template.getString(), callback, false);
if (tag == null) {
return null;
}
}
}
result.add(token);
}
result.add(i < n - 1 ? new OperationToken(c) : new MarkerToken());
}
else if (!Character.isWhitespace(c)) {
templateKeyBuilder.append(c);
}
else {
protected TemplateToken parseTemplateKey(String key, CustomTemplateCallback callback) {
String prefix = getPrefix(key);
boolean useDefaultTag = false;
if (prefix.length() == 0) {
if (!isHtml(callback)) {
return null;
}
}
return result;
}
private static boolean check(@NotNull Collection<Token> tokens) {
State state = State.WORD;
for (Token token : tokens) {
if (token instanceof MarkerToken) {
break;
}
switch (state) {
case OPERATION:
if (token instanceof OperationToken) {
state = ((OperationToken)token).mySign == '*' ? State.NUMBER : State.WORD;
}
else {
return false;
}
break;
case WORD:
if (token instanceof TemplateToken) {
state = State.OPERATION;
}
else {
return false;
}
break;
case NUMBER:
if (token instanceof NumberToken) {
state = State.AFTER_NUMBER;
}
else {
return false;
}
break;
case AFTER_NUMBER:
if (token instanceof OperationToken && ((OperationToken)token).mySign != '*') {
state = State.WORD;
}
else {
return false;
}
break;
else {
useDefaultTag = true;
prefix = DEFAULT_TAG;
key = prefix + key;
}
}
return state == State.OPERATION || state == State.AFTER_NUMBER;
}
private static String computeKey(Editor editor, int startOffset) {
int offset = editor.getCaretModel().getOffset();
String s = editor.getDocument().getCharsSequence().subSequence(startOffset, offset).toString();
int index = 0;
while (index < s.length() && Character.isWhitespace(s.charAt(index))) {
index++;
TemplateImpl template = callback.findApplicableTemplate(prefix);
if (template == null && !isXML11ValidQName(prefix)) {
return null;
}
String key = s.substring(index);
int lastWhitespaceIndex = -1;
for (int i = 0; i < key.length(); i++) {
if (Character.isWhitespace(key.charAt(i))) {
lastWhitespaceIndex = i;
}
TemplateToken token = parseSelectors(key);
if (token == null) {
return null;
}
if (lastWhitespaceIndex >= 0 && lastWhitespaceIndex < key.length() - 1) {
return key.substring(lastWhitespaceIndex + 1);
if (useDefaultTag && token.myAttribute2Value.size() == 0) {
return null;
}
return key;
}
public String computeTemplateKey(@NotNull CustomTemplateCallback callback) {
return computeKey(callback);
}
static String computeKey(CustomTemplateCallback callback) {
Editor editor = callback.getEditor();
PsiElement element = callback.getContext();
int line = editor.getCaretModel().getLogicalPosition().line;
int lineStart = editor.getDocument().getLineStartOffset(line);
int parentStart;
do {
parentStart = element != null ? element.getTextRange().getStartOffset() : 0;
int startOffset = parentStart > lineStart ? parentStart : lineStart;
String key = computeKey(editor, startOffset);
if (checkTemplateKey(key, callback)) {
return key;
}
if (element != null) {
element = element.getParent();
}
}
while (element != null && parentStart > lineStart);
return null;
}
private static boolean checkTemplateKey(String key, CustomTemplateCallback callback) {
List<Token> tokens = parse(key, callback);
if (tokens != null && check(tokens)) {
// !! required if Zen Coding if invoked by TemplateManagerImpl action
/*if (tokens.size() == 2) {
Token token = tokens.get(0);
if (token instanceof TemplateToken) {
if (key.equals(((TemplateToken)token).myKey) && callback.isLiveTemplateApplicable(key)) {
// do not activate only live template
return null;
}
if (template != null && (token.myAttribute2Value.size() > 0 || isTrueXml(callback))) {
assert prefix.equals(token.myKey);
token.myTemplate = template;
if (token.myAttribute2Value.size() > 0) {
XmlTag tag = parseXmlTagInTemplate(template.getString(), callback, false);
if (tag == null) {
return null;
}
}*/
return true;
}
return false;
}
public boolean isApplicable(PsiFile file, int offset, boolean selection) {
return isApplicable(file, offset);
}
private static boolean isApplicable(PsiFile file, int offset) {
WebEditorOptions webEditorOptions = WebEditorOptions.getInstance();
if (!webEditorOptions.isZenCodingEnabled()) {
return false;
}
if (file == null) {
return false;
}
PsiDocumentManager.getInstance(file.getProject()).commitAllDocuments();
PsiElement element = null;
if (!InjectedLanguageManager.getInstance(file.getProject()).isInjectedFragment(file)) {
element = InjectedLanguageUtil.findInjectedElementNoCommit(file, offset);
}
if (element == null) {
element = file.findElementAt(offset > 0 ? offset - 1 : offset);
if (element == null) {
element = file;
}
}
return token;
}
@Nullable
static XmlTag parseXmlTagInTemplate(String templateString, CustomTemplateCallback callback, boolean createPhysicalFile) {
XmlFile xmlFile = (XmlFile)PsiFileFactory.getInstance(callback.getProject())
.createFileFromText("dummy.xml", StdFileTypes.XML, templateString, LocalTimeCounter.currentTime(), createPhysicalFile);
XmlDocument document = xmlFile.getDocument();
return document == null ? null : document.getRootTag();
}
protected boolean isApplicable(@NotNull PsiElement element) {
if (element.getLanguage() instanceof XMLLanguage) {
if (PsiTreeUtil.getParentOfType(element, XmlAttributeValue.class) != null) {
return false;
@@ -376,111 +226,25 @@ public class XmlZenCodingTemplate implements CustomLiveTemplate {
return false;
}
public void expand(String key, @NotNull CustomTemplateCallback callback) {
expand(key, callback, null);
}
private static void expand(String key,
@NotNull CustomTemplateCallback callback,
String surroundedText) {
List<Token> tokens = parse(key, callback);
assert tokens != null;
if (surroundedText == null) {
if (tokens.size() == 2) {
Token token = tokens.get(0);
if (token instanceof TemplateToken) {
if (key.equals(((TemplateToken)token).myKey) && callback.findApplicableTemplates(key).size() > 1) {
callback.startTemplate();
return;
}
}
}
callback.deleteTemplateKey(key);
}
XmlZenCodingInterpreter.interpret(tokens, 0, callback, State.WORD, surroundedText);
}
public void wrap(final String selection,
@NotNull final CustomTemplateCallback callback,
@Nullable final TemplateInvokationListener listener) {
InputValidatorEx validator = new InputValidatorEx() {
public String getErrorText(String inputString) {
if (!checkTemplateKey(inputString, callback)) {
return XmlBundle.message("zen.coding.incorrect.abbreviation.error");
}
return null;
}
public boolean checkInput(String inputString) {
return getErrorText(inputString) == null;
}
public boolean canClose(String inputString) {
return checkInput(inputString);
}
};
final String abbreviation = Messages
.showInputDialog(callback.getProject(), XmlBundle.message("zen.coding.enter.abbreviation.dialog.label"),
XmlBundle.message("zen.coding.title"), Messages.getQuestionIcon(), "", validator);
if (abbreviation != null) {
doWrap(selection, abbreviation, callback, listener);
}
}
private static void doWrap(final String selection,
final String abbreviation,
final CustomTemplateCallback callback,
final TemplateInvokationListener listener) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
CommandProcessor.getInstance().executeCommand(callback.getProject(), new Runnable() {
public void run() {
EditorModificationUtil.deleteSelectedText(callback.getEditor());
PsiDocumentManager.getInstance(callback.getProject()).commitAllDocuments();
callback.fixInitialState();
expand(abbreviation, callback, selection);
if (listener != null) {
listener.finished();
}
}
}, CodeInsightBundle.message("insert.code.template.command"), null);
}
});
}
@NotNull
public String getTitle() {
return XmlBundle.message("zen.coding.title");
}
public char getShortcut() {
return (char)WebEditorOptions.getInstance().getZenCodingExpandShortcut();
}
@Nullable
static XmlTag parseXmlTagInTemplate(String templateString, CustomTemplateCallback callback, boolean createPhysicalFile) {
XmlFile xmlFile = (XmlFile)PsiFileFactory.getInstance(callback.getProject())
.createFileFromText("dummy.xml", StdFileTypes.XML, templateString, LocalTimeCounter.currentTime(), createPhysicalFile);
XmlDocument document = xmlFile.getDocument();
return document == null ? null : document.getRootTag();
}
public static boolean startZenCoding(Editor editor, PsiFile file, String abbreviation) {
int caretAt = editor.getCaretModel().getOffset();
if (isApplicable(file, caretAt)) {
XmlZenCodingTemplate template = CustomLiveTemplate.EP_NAME.findExtension(XmlZenCodingTemplate.class);
if (abbreviation != null && !template.supportsWrapping()) {
return false;
}
if (template.isApplicable(file, caretAt)) {
final CustomTemplateCallback callback = new CustomTemplateCallback(editor, file);
if (abbreviation != null) {
String selection = callback.getEditor().getSelectionModel().getSelectedText();
assert selection != null;
selection = selection.trim();
doWrap(selection, abbreviation, callback, new TemplateInvokationListener() {
template.doWrap(selection, abbreviation, callback, new TemplateInvokationListener() {
public void finished() {
callback.startAllExpandedTemplates();
}
});
}
else {
XmlZenCodingTemplate template = new XmlZenCodingTemplate();
String key = template.computeTemplateKey(callback);
if (key != null) {
template.expand(key, callback);
@@ -494,4 +258,29 @@ public class XmlZenCodingTemplate implements CustomLiveTemplate {
}
return false;
}
public String computeTemplateKey(@NotNull CustomTemplateCallback callback) {
Editor editor = callback.getEditor();
PsiElement element = callback.getContext();
int line = editor.getCaretModel().getLogicalPosition().line;
int lineStart = editor.getDocument().getLineStartOffset(line);
int elementStart;
do {
elementStart = element != null ? element.getTextRange().getStartOffset() : 0;
int startOffset = elementStart > lineStart ? elementStart : lineStart;
String key = computeKey(editor, startOffset);
if (checkTemplateKey(key, callback)) {
return key;
}
if (element != null) {
element = element.getParent();
}
}
while (element != null && elementStart > lineStart);
return null;
}
public boolean supportsWrapping() {
return true;
}
}
@@ -0,0 +1,267 @@
/*
* Copyright 2000-2010 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.codeInsight.template.zencoding;
import com.intellij.application.options.editor.WebEditorOptions;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.template.CustomLiveTemplate;
import com.intellij.codeInsight.template.CustomTemplateCallback;
import com.intellij.codeInsight.template.TemplateInvokationListener;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorModificationUtil;
import com.intellij.openapi.ui.InputValidatorEx;
import com.intellij.openapi.ui.Messages;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.xml.XmlBundle;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @author Eugene.Kudelevsky
*/
public abstract class ZenCodingTemplate implements CustomLiveTemplate {
static final char MARKER = '$';
private static final String OPERATIONS = ">+*";
private static int parseNonNegativeInt(@NotNull String s) {
try {
return Integer.parseInt(s);
}
catch (Throwable ignored) {
}
return -1;
}
@Nullable
private List<Token> parse(@NotNull String text, @NotNull CustomTemplateCallback callback) {
text += MARKER;
StringBuilder templateKeyBuilder = new StringBuilder();
List<Token> result = new ArrayList<Token>();
for (int i = 0, n = text.length(); i < n; i++) {
char c = text.charAt(i);
if (i == n - 1 || (i < n - 2 && OPERATIONS.indexOf(c) >= 0)) {
String key = templateKeyBuilder.toString();
templateKeyBuilder = new StringBuilder();
int num = parseNonNegativeInt(key);
if (num > 0) {
result.add(new NumberToken(num));
}
else {
TemplateToken token = parseTemplateKey(key, callback);
if (token == null) return null;
result.add(token);
}
result.add(i < n - 1 ? new OperationToken(c) : new MarkerToken());
}
else if (!Character.isWhitespace(c)) {
templateKeyBuilder.append(c);
}
else {
return null;
}
}
return result;
}
@Nullable
protected abstract TemplateToken parseTemplateKey(String key, CustomTemplateCallback callback);
private static boolean check(@NotNull Collection<Token> tokens) {
State state = State.WORD;
for (Token token : tokens) {
if (token instanceof MarkerToken) {
break;
}
switch (state) {
case OPERATION:
if (token instanceof OperationToken) {
state = ((OperationToken)token).mySign == '*' ? State.NUMBER : State.WORD;
}
else {
return false;
}
break;
case WORD:
if (token instanceof TemplateToken) {
state = State.OPERATION;
}
else {
return false;
}
break;
case NUMBER:
if (token instanceof NumberToken) {
state = State.AFTER_NUMBER;
}
else {
return false;
}
break;
case AFTER_NUMBER:
if (token instanceof OperationToken && ((OperationToken)token).mySign != '*') {
state = State.WORD;
}
else {
return false;
}
break;
}
}
return state == State.OPERATION || state == State.AFTER_NUMBER;
}
protected static String computeKey(Editor editor, int startOffset) {
int offset = editor.getCaretModel().getOffset();
String s = editor.getDocument().getCharsSequence().subSequence(startOffset, offset).toString();
int index = 0;
while (index < s.length() && Character.isWhitespace(s.charAt(index))) {
index++;
}
String key = s.substring(index);
int lastWhitespaceIndex = -1;
for (int i = 0; i < key.length(); i++) {
if (Character.isWhitespace(key.charAt(i))) {
lastWhitespaceIndex = i;
}
}
if (lastWhitespaceIndex >= 0 && lastWhitespaceIndex < key.length() - 1) {
return key.substring(lastWhitespaceIndex + 1);
}
return key;
}
protected boolean checkTemplateKey(String key, CustomTemplateCallback callback) {
List<Token> tokens = parse(key, callback);
if (tokens != null && check(tokens)) {
// !! required if Zen Coding if invoked by TemplateManagerImpl action
/*if (tokens.size() == 2) {
Token token = tokens.get(0);
if (token instanceof TemplateToken) {
if (key.equals(((TemplateToken)token).myKey) && callback.isLiveTemplateApplicable(key)) {
// do not activate only live template
return null;
}
}
}*/
return true;
}
return false;
}
public void expand(String key, @NotNull CustomTemplateCallback callback) {
expand(key, callback, null);
}
private void expand(String key,
@NotNull CustomTemplateCallback callback,
String surroundedText) {
List<Token> tokens = parse(key, callback);
assert tokens != null;
if (surroundedText == null) {
if (tokens.size() == 2) {
Token token = tokens.get(0);
if (token instanceof TemplateToken) {
if (key.equals(((TemplateToken)token).myKey) && callback.findApplicableTemplates(key).size() > 1) {
callback.startTemplate();
return;
}
}
}
callback.deleteTemplateKey(key);
}
XmlZenCodingInterpreter.interpret(tokens, 0, callback, State.WORD, surroundedText);
}
public void wrap(final String selection,
@NotNull final CustomTemplateCallback callback,
@Nullable final TemplateInvokationListener listener) {
InputValidatorEx validator = new InputValidatorEx() {
public String getErrorText(String inputString) {
if (!checkTemplateKey(inputString, callback)) {
return XmlBundle.message("zen.coding.incorrect.abbreviation.error");
}
return null;
}
public boolean checkInput(String inputString) {
return getErrorText(inputString) == null;
}
public boolean canClose(String inputString) {
return checkInput(inputString);
}
};
final String abbreviation = Messages
.showInputDialog(callback.getProject(), XmlBundle.message("zen.coding.enter.abbreviation.dialog.label"),
XmlBundle.message("zen.coding.title"), Messages.getQuestionIcon(), "", validator);
if (abbreviation != null) {
doWrap(selection, abbreviation, callback, listener);
}
}
public boolean isApplicable(PsiFile file, int offset) {
WebEditorOptions webEditorOptions = WebEditorOptions.getInstance();
if (!webEditorOptions.isZenCodingEnabled()) {
return false;
}
if (file == null) {
return false;
}
PsiDocumentManager.getInstance(file.getProject()).commitAllDocuments();
PsiElement element = CustomTemplateCallback.getContext(file, offset);
return isApplicable(element);
}
protected abstract boolean isApplicable(@NotNull PsiElement element);
protected void doWrap(final String selection,
final String abbreviation,
final CustomTemplateCallback callback,
final TemplateInvokationListener listener) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
CommandProcessor.getInstance().executeCommand(callback.getProject(), new Runnable() {
public void run() {
EditorModificationUtil.deleteSelectedText(callback.getEditor());
PsiDocumentManager.getInstance(callback.getProject()).commitAllDocuments();
callback.fixInitialState();
expand(abbreviation, callback, selection);
if (listener != null) {
listener.finished();
}
}
}, CodeInsightBundle.message("insert.code.template.command"), null);
}
});
}
@NotNull
public String getTitle() {
return XmlBundle.message("zen.coding.title");
}
public char getShortcut() {
return (char)WebEditorOptions.getInstance().getZenCodingExpandShortcut();
}
}