Merge branch 'master' of git.labs.intellij.net:idea/community

This commit is contained in:
Rustam.Vishnyakov
2010-09-01 15:46:12 +04:00
31 changed files with 790 additions and 325 deletions
@@ -116,7 +116,7 @@ public class DeclarationParser {
}
}
declaration.done(JavaElementType.CLASS);
done(declaration, JavaElementType.CLASS);
return declaration;
}
@@ -162,10 +162,10 @@ public class DeclarationParser {
if (builder.getTokenType() == JavaTokenType.LBRACE) {
final PsiBuilder.Marker constantInit = builder.mark();
parseClassBodyWithBraces(builder, false, false);
constantInit.done(JavaElementType.ENUM_CONSTANT_INITIALIZER);
done(constantInit, JavaElementType.ENUM_CONSTANT_INITIALIZER);
}
constant.done(JavaElementType.ENUM_CONSTANT);
done(constant, JavaElementType.ENUM_CONSTANT);
return constant;
}
else {
@@ -309,7 +309,7 @@ public class DeclarationParser {
final PsiBuilder.Marker error = typeParams.precede();
error.errorBefore(JavaErrorMessages.message("unexpected.token"), codeBlock);
}
declaration.done(JavaElementType.CLASS_INITIALIZER);
done(declaration, JavaElementType.CLASS_INITIALIZER);
return declaration;
}
else {
@@ -391,7 +391,7 @@ public class DeclarationParser {
}
}
modList.done(JavaElementType.MODIFIER_LIST);
done(modList, JavaElementType.MODIFIER_LIST);
return Pair.create(modList, isEmpty);
}
@@ -405,7 +405,7 @@ public class DeclarationParser {
final PsiBuilder.Marker receiver = builder.mark();
final PsiBuilder.Marker annotations = parseAnnotations(builder);
if (annotations != null) {
receiver.done(JavaElementType.METHOD_RECEIVER);
done(receiver, JavaElementType.METHOD_RECEIVER);
}
else {
receiver.drop();
@@ -441,7 +441,7 @@ public class DeclarationParser {
}
}
declaration.done(anno ? JavaElementType.ANNOTATION_METHOD : JavaElementType.METHOD);
done(declaration, anno ? JavaElementType.ANNOTATION_METHOD : JavaElementType.METHOD);
return declaration;
}
@@ -528,7 +528,7 @@ public class DeclarationParser {
invalidElements.error(errorMessage);
}
paramList.done(JavaElementType.PARAMETER_LIST);
done(paramList, JavaElementType.PARAMETER_LIST);
return paramList;
}
@@ -552,7 +552,7 @@ public class DeclarationParser {
if (expect(builder, JavaTokenType.IDENTIFIER)) {
eatBrackets(builder);
param.done(JavaElementType.PARAMETER);
done(param, JavaElementType.PARAMETER);
return param;
}
else {
@@ -603,7 +603,7 @@ public class DeclarationParser {
}
if (builder.getTokenType() != JavaTokenType.COMMA) break;
variable.done(varType);
done(variable, varType);
builder.advanceLexer();
if (builder.getTokenType() != JavaTokenType.IDENTIFIER) {
@@ -642,7 +642,7 @@ public class DeclarationParser {
}
if (openMarker) {
variable.done(varType);
done(variable, varType);
}
return declaration;
@@ -683,7 +683,7 @@ public class DeclarationParser {
parseAnnotationParameterList(builder);
anno.done(JavaElementType.ANNOTATION);
done(anno, JavaElementType.ANNOTATION);
return anno;
}
@@ -692,12 +692,12 @@ public class DeclarationParser {
PsiBuilder.Marker list = builder.mark();
if (!expect(builder, JavaTokenType.LPARENTH)) {
list.done(JavaElementType.ANNOTATION_PARAMETER_LIST);
done(list, JavaElementType.ANNOTATION_PARAMETER_LIST);
return list;
}
if (expect(builder, JavaTokenType.RPARENTH)) {
list.done(JavaElementType.ANNOTATION_PARAMETER_LIST);
done(list, JavaElementType.ANNOTATION_PARAMETER_LIST);
return list;
}
@@ -739,7 +739,7 @@ public class DeclarationParser {
}
}
list.done(JavaElementType.ANNOTATION_PARAMETER_LIST);
done(list, JavaElementType.ANNOTATION_PARAMETER_LIST);
return list;
}
@@ -749,7 +749,7 @@ public class DeclarationParser {
if (mayBeSimple) {
parseAnnotationValue(builder);
if (builder.getTokenType() != JavaTokenType.EQ) {
pair.done(JavaElementType.NAME_VALUE_PAIR);
done(pair, JavaElementType.NAME_VALUE_PAIR);
return false;
}
@@ -763,7 +763,7 @@ public class DeclarationParser {
parseAnnotationValue(builder);
pair.done(JavaElementType.NAME_VALUE_PAIR);
done(pair, JavaElementType.NAME_VALUE_PAIR);
return hasName;
}
@@ -798,7 +798,7 @@ public class DeclarationParser {
builder.advanceLexer();
if (expect(builder, JavaTokenType.RBRACE)) {
annoArray.done(JavaElementType.ANNOTATION_ARRAY_INITIALIZER);
done(annoArray, JavaElementType.ANNOTATION_ARRAY_INITIALIZER);
return annoArray;
}
@@ -819,7 +819,7 @@ public class DeclarationParser {
}
}
annoArray.done(JavaElementType.ANNOTATION_ARRAY_INITIALIZER);
done(annoArray, JavaElementType.ANNOTATION_ARRAY_INITIALIZER);
if (unclosed) {
annoArray.setCustomEdgeProcessors(null, GREEDY_RIGHT_EDGE_PROCESSOR);
}
@@ -27,38 +27,61 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.intellij.lang.PsiBuilderUtil.expect;
import static com.intellij.lang.java.parser.JavaParserUtil.done;
import static com.intellij.lang.java.parser.JavaParserUtil.semicolon;
public class FileParser {
public interface TopLevelDeclarationParser {
@Nullable PsiBuilder.Marker parse(PsiBuilder builder);
}
private static final TokenSet IMPORT_LIST_STOPPER_SET = TokenSet.orSet(
ElementType.MODIFIER_BIT_SET,
TokenSet.create(JavaTokenType.CLASS_KEYWORD, JavaTokenType.INTERFACE_KEYWORD, JavaTokenType.ENUM_KEYWORD, JavaTokenType.AT));
private static final TopLevelDeclarationParser TOP_LEVEL_DECLARATION_PARSER = new TopLevelDeclarationParser() {
public PsiBuilder.Marker parse(final PsiBuilder builder) {
return DeclarationParser.parse(builder, DeclarationParser.Context.FILE);
}
};
private FileParser() { }
public static void parse(final PsiBuilder builder) {
parseFile(builder, IMPORT_LIST_STOPPER_SET, TOP_LEVEL_DECLARATION_PARSER, JavaErrorMessages.message("expected.class.or.interface"));
}
public static void parseFile(final PsiBuilder builder, final TokenSet importListStoppers,
final TopLevelDeclarationParser declarationParser, final String errorMessage) {
parsePackageStatement(builder);
parseImportList(builder);
final Pair<PsiBuilder.Marker, Boolean> impListInfo = parseImportList(builder, importListStoppers);
Boolean firstDeclarationOk = null;
PsiBuilder.Marker firstDeclaration = null;
PsiBuilder.Marker invalidElements = null;
while (!builder.eof()) {
if (builder.getTokenType() == JavaTokenType.SEMICOLON) {
if (invalidElements != null) {
invalidElements.error(JavaErrorMessages.message("expected.class.or.interface"));
invalidElements.error(errorMessage);
invalidElements = null;
}
builder.advanceLexer();
if (firstDeclarationOk == null) firstDeclarationOk = false;
continue;
}
final PsiBuilder.Marker declaration = DeclarationParser.parse(builder, DeclarationParser.Context.FILE);
final PsiBuilder.Marker declaration = declarationParser.parse(builder);
if (declaration != null) {
if (invalidElements != null) {
invalidElements.errorBefore(JavaErrorMessages.message("expected.class.or.interface"), declaration);
invalidElements.errorBefore(errorMessage, declaration);
invalidElements = null;
}
if (firstDeclarationOk == null) {
firstDeclarationOk = true;
firstDeclaration = declaration;
}
continue;
}
@@ -66,10 +89,16 @@ public class FileParser {
invalidElements = builder.mark();
}
builder.advanceLexer();
if (firstDeclarationOk == null) firstDeclarationOk = false;
}
if (invalidElements != null) {
invalidElements.error(JavaErrorMessages.message("expected.class.or.interface"));
invalidElements.error(errorMessage);
}
if (impListInfo.second && firstDeclarationOk == Boolean.TRUE) {
impListInfo.first.setCustomEdgeProcessors(JavaParserUtil.PRECEDING_COMMENT_BINDER, null); // pass comments behind fake import list
firstDeclaration.setCustomEdgeProcessors(JavaParserUtil.SPECIAL_PRECEDING_COMMENT_BINDER, null);
}
}
@@ -80,7 +109,7 @@ public class FileParser {
if (!expect(builder, JavaTokenType.PACKAGE_KEYWORD)) {
final PsiBuilder.Marker modList = builder.mark();
DeclarationParser.parseAnnotations(builder);
modList.done(JavaElementType.MODIFIER_LIST);
done(modList, JavaElementType.MODIFIER_LIST);
if (!expect(builder, JavaTokenType.PACKAGE_KEYWORD)) {
statement.rollbackTo();
return null;
@@ -95,15 +124,10 @@ public class FileParser {
semicolon(builder);
statement.done(JavaElementType.PACKAGE_STATEMENT);
done(statement, JavaElementType.PACKAGE_STATEMENT);
return statement;
}
@NotNull
private static Pair<PsiBuilder.Marker, Boolean> parseImportList(final PsiBuilder builder) {
return parseImportList(builder, IMPORT_LIST_STOPPER_SET);
}
@NotNull
public static Pair<PsiBuilder.Marker, Boolean> parseImportList(final PsiBuilder builder, final TokenSet stoppers) {
final PsiBuilder.Marker list = builder.mark();
@@ -134,7 +158,7 @@ public class FileParser {
}
}
list.done(JavaElementType.IMPORT_LIST);
done(list, JavaElementType.IMPORT_LIST);
return Pair.create(list, isEmpty);
}
@@ -153,7 +177,7 @@ public class FileParser {
semicolon(builder);
}
statement.done(type);
done(statement, type);
return statement;
}
}
@@ -19,7 +19,6 @@ import com.intellij.lang.ASTNode;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.PsiParser;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.impl.source.parsing.ParseUtil;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
@@ -41,8 +40,6 @@ public class JavaParser implements PsiParser {
FileParser.parse(builder);
root.done(rootType);
final ASTNode rootNode = builder.getTreeBuilt();
ParseUtil.bindComments(rootNode);
return rootNode;
return builder.getTreeBuilt();
}
}
@@ -18,8 +18,12 @@ package com.intellij.lang.java.parser;
import com.intellij.codeInsight.daemon.JavaErrorMessages;
import com.intellij.lang.*;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.impl.source.tree.ElementType;
import com.intellij.psi.impl.source.tree.JavaDocElementType;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.util.diff.FlyweightCapableTreeStructure;
@@ -34,11 +38,77 @@ public class JavaParserUtil {
private static final Key<LanguageLevel> LANG_LEVEL_KEY = Key.create("JavaParserUtil.LanguageLevel");
public static final WhitespacesAndCommentsProcessor GREEDY_RIGHT_EDGE_PROCESSOR = new WhitespacesAndCommentsProcessor() {
public int process(final List<IElementType> tokens) {
public int process(final List<IElementType> tokens, final boolean atStreamEdge, final TokenTextGetter getter) {
return tokens.size();
}
};
private static class PrecedingWhitespacesAndCommentsProcessor implements WhitespacesAndCommentsProcessor {
private final boolean myAfterEmptyImport;
public PrecedingWhitespacesAndCommentsProcessor(final boolean afterImport) {
this.myAfterEmptyImport = afterImport;
}
public int process(final List<IElementType> tokens, final boolean atStreamEdge, final TokenTextGetter
getter) {
if (tokens.size() == 0) return 0;
// 1. bind doc comment
for (int idx = tokens.size() - 1; idx >= 0; idx--) {
if (tokens.get(idx) == JavaDocElementType.DOC_COMMENT) return idx;
}
// 2. bind plain comments
int result = tokens.size();
for (int idx = tokens.size() - 1; idx >= 0; idx--) {
final IElementType tokenType = tokens.get(idx);
if (ElementType.JAVA_WHITESPACE_BIT_SET.contains(tokenType)) {
if (StringUtil.getLineBreakCount(getter.get(idx)) > 1) break;
}
else if (ElementType.JAVA_PLAIN_COMMENT_BIT_SET.contains(tokenType)) {
if (atStreamEdge ||
(idx == 0 && myAfterEmptyImport) ||
(idx > 0 && ElementType.JAVA_WHITESPACE_BIT_SET.contains(tokens.get(idx - 1)) && StringUtil.containsLineBreak(getter.get(idx - 1)))) {
result = idx;
}
}
else break;
}
return result;
}
}
private static class TrailingWhitespacesAndCommentsProcessor implements WhitespacesAndCommentsProcessor {
public int process(final List<IElementType> tokens, final boolean atStreamEdge, final TokenTextGetter getter) {
if (tokens.size() == 0) return 0;
int result = 0;
for (int idx = 0; idx < tokens.size(); idx++) {
final IElementType tokenType = tokens.get(idx);
if (ElementType.JAVA_WHITESPACE_BIT_SET.contains(tokenType)) {
if (StringUtil.containsLineBreak(getter.get(idx))) break;
}
else if (ElementType.JAVA_PLAIN_COMMENT_BIT_SET.contains(tokenType)) {
result = idx + 1;
}
else break;
}
return result;
}
}
private static final TokenSet PRECEDING_COMMENT_SET = ElementType.FULL_MEMBER_BIT_SET;
private static final TokenSet TRAILING_COMMENT_SET = TokenSet.orSet(
TokenSet.create(JavaElementType.PACKAGE_STATEMENT),
ElementType.IMPORT_STATEMENT_BASE_BIT_SET, ElementType.FULL_MEMBER_BIT_SET, ElementType.JAVA_STATEMENT_BIT_SET);
public static final WhitespacesAndCommentsProcessor PRECEDING_COMMENT_BINDER = new PrecedingWhitespacesAndCommentsProcessor(false);
public static final WhitespacesAndCommentsProcessor SPECIAL_PRECEDING_COMMENT_BINDER = new PrecedingWhitespacesAndCommentsProcessor(true);
public static final WhitespacesAndCommentsProcessor TRAILING_COMMENT_BINDER = new TrailingWhitespacesAndCommentsProcessor();
private JavaParserUtil() { }
public static void setLanguageLevel(final PsiBuilder builder, final LanguageLevel level) {
@@ -57,12 +127,19 @@ public class JavaParserUtil {
return level;
}
public static void done(final PsiBuilder.Marker marker, final IElementType type) {
marker.done(type);
final WhitespacesAndCommentsProcessor left = PRECEDING_COMMENT_SET.contains(type) ? PRECEDING_COMMENT_BINDER : null;
final WhitespacesAndCommentsProcessor right = TRAILING_COMMENT_SET.contains(type) ? TRAILING_COMMENT_BINDER : null;
marker.setCustomEdgeProcessors(left, right);
}
@Nullable
public static IElementType exprType(@Nullable final PsiBuilder.Marker marker) {
return marker != null ? ((LighterASTNode)marker).getTokenType() : null;
}
// used instead of PsiBuilder.error() as it drops all but first subsequent error messages
// used instead of PsiBuilder.error() as it keeps all subsequent error messages
public static void error(final PsiBuilder builder, final String message) {
builder.mark().error(message);
}
@@ -118,7 +118,7 @@ public class StatementParser {
final boolean greedyBlock = !expectOrError(builder, JavaTokenType.RBRACE, JavaErrorMessages.message("expected.rbrace"));
codeBlock.done(JavaElementType.CODE_BLOCK);
done(codeBlock, JavaElementType.CODE_BLOCK);
if (greedyBlock) {
codeBlock.setCustomEdgeProcessors(null, GREEDY_RIGHT_EDGE_PROCESSOR);
}
@@ -214,7 +214,7 @@ public class StatementParser {
else if (tokenType == JavaTokenType.SEMICOLON) {
final PsiBuilder.Marker empty = builder.mark();
builder.advanceLexer();
empty.done(JavaElementType.EMPTY_STATEMENT);
done(empty, JavaElementType.EMPTY_STATEMENT);
return empty;
}
else if (tokenType == JavaTokenType.IDENTIFIER || tokenType == JavaTokenType.AT) {
@@ -230,7 +230,7 @@ public class StatementParser {
ReferenceParser.parseType(builder, false, false);
error(builder, JavaErrorMessages.message("expected.identifier"));
}
declStatement.done(JavaElementType.DECLARATION_STATEMENT);
done(declStatement, JavaElementType.DECLARATION_STATEMENT);
return declStatement;
}
}
@@ -255,15 +255,15 @@ public class StatementParser {
}
if (count > 1) {
pos.drop();
list.done(JavaElementType.EXPRESSION_LIST);
done(list, JavaElementType.EXPRESSION_LIST);
semicolon(builder);
statement.done(JavaElementType.EXPRESSION_LIST_STATEMENT);
done(statement, JavaElementType.EXPRESSION_LIST_STATEMENT);
return statement;
}
if (exprType(expr) != JavaElementType.REFERENCE_EXPRESSION) {
drop(list, pos);
semicolon(builder);
statement.done(JavaElementType.EXPRESSION_STATEMENT);
done(statement, JavaElementType.EXPRESSION_STATEMENT);
return statement;
}
pos.rollbackTo();
@@ -275,7 +275,7 @@ public class StatementParser {
final PsiBuilder.Marker decl = DeclarationParser.parse(builder, DeclarationParser.Context.CODE_BLOCK);
if (decl != null) {
final PsiBuilder.Marker statement = decl.precede();
statement.done(JavaElementType.DECLARATION_STATEMENT);
done(statement, JavaElementType.DECLARATION_STATEMENT);
return statement;
}
@@ -283,7 +283,7 @@ public class StatementParser {
final PsiBuilder.Marker statement = builder.mark();
advance(builder, 2);
parseStatement(builder);
statement.done(JavaElementType.LABELED_STATEMENT);
done(statement, JavaElementType.LABELED_STATEMENT);
return statement;
}
@@ -291,7 +291,7 @@ public class StatementParser {
final PsiBuilder.Marker statement = builder.mark();
ExpressionParser.parse(builder);
semicolon(builder);
statement.done(JavaElementType.EXPRESSION_STATEMENT);
done(statement, JavaElementType.EXPRESSION_STATEMENT);
return statement;
}
@@ -311,19 +311,19 @@ public class StatementParser {
builder.advanceLexer();
if (!parseExpressionInParenth(builder)) {
statement.done(JavaElementType.IF_STATEMENT);
done(statement, JavaElementType.IF_STATEMENT);
return statement;
}
final PsiBuilder.Marker thenStatement = parseStatement(builder);
if (thenStatement == null) {
error(builder, JavaErrorMessages.message("expected.statement"));
statement.done(JavaElementType.IF_STATEMENT);
done(statement, JavaElementType.IF_STATEMENT);
return statement;
}
if (!expect(builder, JavaTokenType.ELSE_KEYWORD)) {
statement.done(JavaElementType.IF_STATEMENT);
done(statement, JavaElementType.IF_STATEMENT);
return statement;
}
@@ -332,7 +332,7 @@ public class StatementParser {
error(builder, JavaErrorMessages.message("expected.statement"));
}
statement.done(JavaElementType.IF_STATEMENT);
done(statement, JavaElementType.IF_STATEMENT);
return statement;
}
@@ -342,7 +342,7 @@ public class StatementParser {
builder.advanceLexer();
if (!parseExpressionInParenth(builder)) {
statement.done(JavaElementType.WHILE_STATEMENT);
done(statement, JavaElementType.WHILE_STATEMENT);
return statement;
}
@@ -351,7 +351,7 @@ public class StatementParser {
error(builder, JavaErrorMessages.message("expected.statement"));
}
statement.done(JavaElementType.WHILE_STATEMENT);
done(statement, JavaElementType.WHILE_STATEMENT);
return statement;
}
@@ -362,7 +362,7 @@ public class StatementParser {
if (!expect(builder, JavaTokenType.LPARENTH)) {
error(builder, JavaErrorMessages.message("expected.lparen"));
statement.done(JavaElementType.FOR_STATEMENT);
done(statement, JavaElementType.FOR_STATEMENT);
return statement;
}
@@ -384,7 +384,7 @@ public class StatementParser {
if (init == null){
error(builder, JavaErrorMessages.message("expected.statement"));
if (!expect(builder, JavaTokenType.RPARENTH)) {
statement.done(JavaElementType.FOR_STATEMENT);
done(statement, JavaElementType.FOR_STATEMENT);
return statement;
}
}
@@ -393,7 +393,7 @@ public class StatementParser {
if (!expect(builder, JavaTokenType.SEMICOLON)) {
error(builder, JavaErrorMessages.message("expected.semicolon"));
if (!expect(builder, JavaTokenType.RPARENTH)) {
statement.done(JavaElementType.FOR_STATEMENT);
done(statement, JavaElementType.FOR_STATEMENT);
return statement;
}
}
@@ -401,7 +401,7 @@ public class StatementParser {
parseExpressionOrExpressionList(builder);
if (!expect(builder, JavaTokenType.RPARENTH)) {
error(builder, JavaErrorMessages.message("expected.rparen"));
statement.done(JavaElementType.FOR_STATEMENT);
done(statement, JavaElementType.FOR_STATEMENT);
return statement;
}
}
@@ -412,7 +412,7 @@ public class StatementParser {
error(builder, JavaErrorMessages.message("expected.statement"));
}
statement.done(JavaElementType.FOR_STATEMENT);
done(statement, JavaElementType.FOR_STATEMENT);
return statement;
}
@@ -423,7 +423,7 @@ public class StatementParser {
final PsiBuilder.Marker expressionStatement;
if (builder.getTokenType() != JavaTokenType.COMMA) {
expressionStatement = expr.precede();
expressionStatement.done(JavaElementType.EXPRESSION_STATEMENT);
done(expressionStatement, JavaElementType.EXPRESSION_STATEMENT);
}
else {
final PsiBuilder.Marker expressionList = expr.precede();
@@ -438,8 +438,8 @@ public class StatementParser {
}
while (builder.getTokenType() == JavaTokenType.COMMA);
expressionList.done(JavaElementType.EXPRESSION_LIST);
expressionStatement.done(JavaElementType.EXPRESSION_LIST_STATEMENT);
done(expressionList, JavaElementType.EXPRESSION_LIST);
done(expressionStatement, JavaElementType.EXPRESSION_LIST_STATEMENT);
}
}
@@ -462,7 +462,7 @@ public class StatementParser {
error(builder, JavaErrorMessages.message("expected.rparen"));
}
statement.done(JavaElementType.FOREACH_STATEMENT);
done(statement, JavaElementType.FOREACH_STATEMENT);
return statement;
}
@@ -474,13 +474,13 @@ public class StatementParser {
final PsiBuilder.Marker body = parseStatement(builder);
if (body == null) {
error(builder, JavaErrorMessages.message("expected.statement"));
statement.done(JavaElementType.DO_WHILE_STATEMENT);
done(statement, JavaElementType.DO_WHILE_STATEMENT);
return statement;
}
if (!expect(builder, JavaTokenType.WHILE_KEYWORD)) {
error(builder, JavaErrorMessages.message("expected.while"));
statement.done(JavaElementType.DO_WHILE_STATEMENT);
done(statement, JavaElementType.DO_WHILE_STATEMENT);
return statement;
}
@@ -488,7 +488,7 @@ public class StatementParser {
semicolon(builder);
}
statement.done(JavaElementType.DO_WHILE_STATEMENT);
done(statement, JavaElementType.DO_WHILE_STATEMENT);
return statement;
}
@@ -498,7 +498,7 @@ public class StatementParser {
builder.advanceLexer();
if (!parseExpressionInParenth(builder)) {
statement.done(JavaElementType.SWITCH_STATEMENT);
done(statement, JavaElementType.SWITCH_STATEMENT);
return statement;
}
@@ -507,7 +507,7 @@ public class StatementParser {
error(builder, JavaErrorMessages.message("expected.lbrace"));
}
statement.done(JavaElementType.SWITCH_STATEMENT);
done(statement, JavaElementType.SWITCH_STATEMENT);
return statement;
}
@@ -527,7 +527,7 @@ public class StatementParser {
expectOrError(builder, JavaTokenType.COLON, JavaErrorMessages.message("expected.colon"));
statement.done(JavaElementType.SWITCH_LABEL_STATEMENT);
done(statement, JavaElementType.SWITCH_LABEL_STATEMENT);
return statement;
}
@@ -537,7 +537,7 @@ public class StatementParser {
builder.advanceLexer();
expect(builder, JavaTokenType.IDENTIFIER);
semicolon(builder);
statement.done(JavaElementType.BREAK_STATEMENT);
done(statement, JavaElementType.BREAK_STATEMENT);
return statement;
}
@@ -547,7 +547,7 @@ public class StatementParser {
builder.advanceLexer();
expect(builder, JavaTokenType.IDENTIFIER);
semicolon(builder);
statement.done(JavaElementType.CONTINUE_STATEMENT);
done(statement, JavaElementType.CONTINUE_STATEMENT);
return statement;
}
@@ -559,7 +559,7 @@ public class StatementParser {
ExpressionParser.parse(builder);
semicolon(builder);
statement.done(JavaElementType.RETURN_STATEMENT);
done(statement, JavaElementType.RETURN_STATEMENT);
return statement;
}
@@ -571,12 +571,12 @@ public class StatementParser {
final PsiBuilder.Marker expr = ExpressionParser.parse(builder);
if (expr == null) {
error(builder, JavaErrorMessages.message("expected.expression"));
statement.done(JavaElementType.THROW_STATEMENT);
done(statement, JavaElementType.THROW_STATEMENT);
return statement;
}
semicolon(builder);
statement.done(JavaElementType.THROW_STATEMENT);
done(statement, JavaElementType.THROW_STATEMENT);
return statement;
}
@@ -586,7 +586,7 @@ public class StatementParser {
builder.advanceLexer();
if (!parseExpressionInParenth(builder)) {
statement.done(JavaElementType.SYNCHRONIZED_STATEMENT);
done(statement, JavaElementType.SYNCHRONIZED_STATEMENT);
return statement;
}
@@ -595,7 +595,7 @@ public class StatementParser {
error(builder, JavaErrorMessages.message("expected.lbrace"));
}
statement.done(JavaElementType.SYNCHRONIZED_STATEMENT);
done(statement, JavaElementType.SYNCHRONIZED_STATEMENT);
return statement;
}
@@ -607,13 +607,13 @@ public class StatementParser {
final PsiBuilder.Marker tryBlock = parseCodeBlock(builder);
if (tryBlock == null) {
error(builder, JavaErrorMessages.message("expected.lbrace"));
statement.done(JavaElementType.TRY_STATEMENT);
done(statement, JavaElementType.TRY_STATEMENT);
return statement;
}
if (!TRY_CLOSERS_SET.contains(builder.getTokenType())) {
error(builder, JavaErrorMessages.message("expected.catch.or.finally"));
statement.done(JavaElementType.TRY_STATEMENT);
done(statement, JavaElementType.TRY_STATEMENT);
return statement;
}
@@ -628,7 +628,7 @@ public class StatementParser {
}
}
statement.done(JavaElementType.TRY_STATEMENT);
done(statement, JavaElementType.TRY_STATEMENT);
return statement;
}
@@ -638,7 +638,7 @@ public class StatementParser {
if (!expect(builder, JavaTokenType.LPARENTH)) {
error(builder, JavaErrorMessages.message("expected.lparen"));
section.done(JavaElementType.CATCH_SECTION);
done(section, JavaElementType.CATCH_SECTION);
return false;
}
@@ -649,18 +649,18 @@ public class StatementParser {
if (!expect(builder, JavaTokenType.RPARENTH)) {
error(builder, JavaErrorMessages.message("expected.rparen"));
section.done(JavaElementType.CATCH_SECTION);
done(section, JavaElementType.CATCH_SECTION);
return false;
}
final PsiBuilder.Marker body = parseCodeBlock(builder);
if (body == null) {
error(builder, JavaErrorMessages.message("expected.lbrace"));
section.done(JavaElementType.CATCH_SECTION);
done(section, JavaElementType.CATCH_SECTION);
return false;
}
section.done(JavaElementType.CATCH_SECTION);
done(section, JavaElementType.CATCH_SECTION);
return true;
}
@@ -672,7 +672,7 @@ public class StatementParser {
final PsiBuilder.Marker expr = ExpressionParser.parse(builder);
if (expr == null) {
error(builder, JavaErrorMessages.message("expected.boolean.expression"));
statement.done(JavaElementType.ASSERT_STATEMENT);
done(statement, JavaElementType.ASSERT_STATEMENT);
return statement;
}
@@ -680,13 +680,13 @@ public class StatementParser {
final PsiBuilder.Marker expr2 = ExpressionParser.parse(builder);
if (expr2 == null) {
error(builder, JavaErrorMessages.message("expected.expression"));
statement.done(JavaElementType.ASSERT_STATEMENT);
done(statement, JavaElementType.ASSERT_STATEMENT);
return statement;
}
}
semicolon(builder);
statement.done(JavaElementType.ASSERT_STATEMENT);
done(statement, JavaElementType.ASSERT_STATEMENT);
return statement;
}
@@ -694,7 +694,7 @@ public class StatementParser {
private static PsiBuilder.Marker parseBlockStatement(final PsiBuilder builder) {
final PsiBuilder.Marker statement = builder.mark();
parseCodeBlock(builder);
statement.done(JavaElementType.BLOCK_STATEMENT);
done(statement, JavaElementType.BLOCK_STATEMENT);
return statement;
}
@@ -52,10 +52,6 @@ public class ParseUtil extends ParseUtilBase {
inserter.invoke();
}
public static void bindComments(final ASTNode root) {
JavaMissingTokenInserter.bindComments(root);
}
private static class JavaMissingTokenInserter extends MissingTokenInserter {
public JavaMissingTokenInserter(final CompositeElement root,
final Lexer lexer,
@@ -23,13 +23,9 @@ import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.SingleRootFileViewProvider;
import com.intellij.psi.*;
import com.intellij.psi.impl.JavaPsiFacadeEx;
import com.intellij.psi.impl.source.PsiJavaFileImpl;
import com.intellij.psi.impl.source.parsing.ParseUtil;
import com.intellij.psi.impl.source.tree.FileElement;
import com.intellij.psi.tree.IFileElementType;
import com.intellij.testFramework.IdeaTestCase;
@@ -97,7 +93,6 @@ public abstract class JavaParsingTestCase extends ParsingTestCase {
root.done(this);
final ASTNode rootNode = builder.getTreeBuilt();
ParseUtil.bindComments(rootNode);
return rootNode.getFirstChildNode();
}
};
@@ -116,7 +111,9 @@ public abstract class JavaParsingTestCase extends ParsingTestCase {
}
private static PsiBuilder createBuilder(final ASTNode chameleon) {
final Project project = chameleon.getPsi().getProject();
final PsiElement psi = chameleon.getPsi();
assert psi != null : chameleon;
final Project project = psi.getProject();
final PsiBuilderFactory factory = PsiBuilderFactory.getInstance();
final PsiBuilder builder = factory.createBuilder(project, chameleon, chameleon.getElementType().getLanguage(), chameleon.getChars());
@@ -27,6 +27,13 @@ import java.util.List;
* @see com.intellij.lang.PsiBuilder.Marker#setCustomEdgeProcessors(WhitespacesAndCommentsProcessor, WhitespacesAndCommentsProcessor)
*/
public interface WhitespacesAndCommentsProcessor {
/**
* Provides an ability for the processor to get a text of any of given tokens.
*/
interface TokenTextGetter {
CharSequence get(int i);
}
/**
* <p>Analyzes whitespace and comment tokens at element's edge and returns element's edge position relative to these tokens.
* Value returned by left edge processor will be used as a pointer to a first token of element.
@@ -41,7 +48,9 @@ public interface WhitespacesAndCommentsProcessor {
* whitespace or comment after element's end.
*
* @param tokens sequence of whitespace and comment tokens at the element's edge.
* @return position of element's edge relative to given tokens
* @param atStreamEdge true if sequence of tokens is located at the beginning or the end of token stream.
* @param getter token text getter.
* @return position of element's edge relative to given tokens.
*/
int process(List<IElementType> tokens);
int process(List<IElementType> tokens, boolean atStreamEdge, TokenTextGetter getter);
}
@@ -40,7 +40,10 @@ import com.intellij.psi.tree.*;
import com.intellij.util.CharTable;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ThreeState;
import com.intellij.util.containers.*;
import com.intellij.util.containers.CollectionFactory;
import com.intellij.util.containers.Convertor;
import com.intellij.util.containers.LimitedPool;
import com.intellij.util.containers.Stack;
import com.intellij.util.diff.DiffTree;
import com.intellij.util.diff.DiffTreeChangeBuilder;
import com.intellij.util.diff.FlyweightCapableTreeStructure;
@@ -104,13 +107,13 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
});
private static final WhitespacesAndCommentsProcessor DEFAULT_LEFT_EDGE_PROCESSOR = new WhitespacesAndCommentsProcessor() {
public int process(final List<IElementType> tokens) {
public int process(final List<IElementType> tokens, final boolean atStreamEdge, final TokenTextGetter getter) {
return tokens.size();
}
};
private static final WhitespacesAndCommentsProcessor DEFAULT_RIGHT_EDGE_PROCESSOR = new WhitespacesAndCommentsProcessor() {
public int process(final List<IElementType> tokens) {
public int process(final List<IElementType> tokens, final boolean atStreamEdge, final TokenTextGetter getter) {
return 0;
}
};
@@ -827,23 +830,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
markTokenTypeChecked();
for (int i = 1; i < myProduction.size() - 1; i++) {
final ProductionMarker item = myProduction.get(i);
if (item instanceof StartMarker && ((StartMarker)item).myDoneMarker == null) {
LOG.error(UNBALANCED_MESSAGE);
}
final int prevProductionLexIndex = myProduction.get(i - 1).myLexemeIndex;
int wsStartIndex = item.myLexemeIndex;
while (wsStartIndex > prevProductionLexIndex && whitespaceOrComment(myLexTypes[wsStartIndex - 1])) wsStartIndex--;
int wsEndIndex = item.myLexemeIndex;
while (wsEndIndex < myLexemeCount && whitespaceOrComment(myLexTypes[wsEndIndex])) wsEndIndex++;
final List<IElementType> wsTokens = CollectionFactory.arrayList(myLexTypes, wsStartIndex, wsEndIndex);
item.myLexemeIndex = wsStartIndex + item.myEdgeProcessor.process(wsTokens);
}
balanceWhiteSpaces();
rootMarker.firstChild = rootMarker.lastChild = rootMarker.next = null;
StartMarker curNode = rootMarker;
@@ -891,6 +878,33 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
return rootMarker;
}
private void balanceWhiteSpaces() {
for (int i = 1; i < myProduction.size() - 1; i++) {
final ProductionMarker item = myProduction.get(i);
if (item instanceof StartMarker && ((StartMarker)item).myDoneMarker == null) {
LOG.error(UNBALANCED_MESSAGE);
}
final int prevProductionLexIndex = myProduction.get(i - 1).myLexemeIndex;
int idx = item.myLexemeIndex;
while (idx > prevProductionLexIndex && whitespaceOrComment(myLexTypes[idx - 1])) idx--;
final int wsStartIndex = idx;
int wsEndIndex = item.myLexemeIndex;
while (wsEndIndex < myLexemeCount && whitespaceOrComment(myLexTypes[wsEndIndex])) wsEndIndex++;
final List<IElementType> wsTokens = CollectionFactory.arrayList(myLexTypes, wsStartIndex, wsEndIndex);
final boolean atEnd = (wsStartIndex == 0 || wsEndIndex == myLexemeCount);
final WhitespacesAndCommentsProcessor.TokenTextGetter getter = new WhitespacesAndCommentsProcessor.TokenTextGetter() {
public CharSequence get(final int i) {
return myText.subSequence(myLexStarts[wsStartIndex + i], myLexStarts[wsStartIndex + i + 1]);
}
};
item.myLexemeIndex = wsStartIndex + item.myEdgeProcessor.process(wsTokens, atEnd, getter);
}
}
private void bind(CompositeElement ast, StartMarker marker) {
bind(ast, marker, marker.myLexemeIndex);
}
@@ -62,7 +62,9 @@ public abstract class BasePlatformRefactoringAction extends BaseRefactoringActio
protected final RefactoringActionHandler getHandler(DataContext dataContext) {
final Language[] languages = LangDataKeys.CONTEXT_LANGUAGES.getData(dataContext);
if (languages != null) {
PsiElement elementAtCaret = getElementAtCaret(LangDataKeys.EDITOR.getData(dataContext), LangDataKeys.PSI_FILE.getData(dataContext));
Editor editor = LangDataKeys.EDITOR.getData(dataContext);
PsiFile file = LangDataKeys.PSI_FILE.getData(dataContext);
PsiElement elementAtCaret = editor == null || file == null ? null : getElementAtCaret(editor, file);
for (Language language : languages) {
RefactoringActionHandler handler = getHandler(language, elementAtCaret);
if (handler != null) {
@@ -291,14 +291,14 @@ public class LightPsiBuilderTest {
@Test
public void testCustomEdgeProcessors() throws Exception {
final WhitespacesAndCommentsProcessor leftEdgeProcessor = new WhitespacesAndCommentsProcessor() {
public int process(List<IElementType> tokens) {
public int process(List<IElementType> tokens, boolean atStreamEdge, TokenTextGetter getter) {
int pos = tokens.size() - 1;
while (tokens.get(pos) != COMMENT && pos > 0) pos--;
return pos;
}
};
final WhitespacesAndCommentsProcessor rightEdgeProcessor = new WhitespacesAndCommentsProcessor() {
public int process(List<IElementType> tokens) {
public int process(List<IElementType> tokens, boolean atStreamEdge, TokenTextGetter getter) {
int pos = 0;
while (tokens.get(pos) != COMMENT && pos < tokens.size()-1) pos++;
return pos + 1;
@@ -55,7 +55,7 @@ public class HTTPProxySettingsDialog extends DialogWrapper {
}
protected JComponent createCenterPanel() {
return panel.getComponent();
return panel.createComponent();
}
protected Action[] createActions() {
@@ -15,7 +15,10 @@
*/
package com.intellij.util.net;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.util.Comparing;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.event.DocumentListener;
@@ -30,7 +33,7 @@ import java.awt.event.ActionListener;
* Time: 3:52:47 PM
* To change this template use Options | File Templates.
*/
public class HTTPProxySettingsPanel{
public class HTTPProxySettingsPanel implements SearchableConfigurable {
private JPanel myMainPanel;
private JTextField myProxyLoginTextField;
@@ -134,10 +137,32 @@ public class HTTPProxySettingsPanel{
myRememberProxyPasswordCheckBox.setEnabled(enabled);
}
public JComponent getComponent() {
public JComponent createComponent() {
return myMainPanel;
}
@NotNull
public String getId() {
return getHelpTopic();
}
public Runnable enableSearch(final String option) {
return null;
}
@Nls
public String getDisplayName() {
return "HTTP Proxy";
}
public Icon getIcon() {
return null;
}
public String getHelpTopic() {
return "http.proxy";
}
public void addActionListener(final ActionListener actionListener) {
myProxyLoginTextField.addActionListener(actionListener);
DocumentListener docListener = new DocumentListener() {
@@ -161,4 +186,8 @@ public class HTTPProxySettingsPanel{
myRememberProxyPasswordCheckBox.addActionListener(actionListener);
}
@Override
public void disposeUIResources() {
}
}
@@ -15,18 +15,14 @@
*/
package com.intellij.util.net;
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.util.DefaultJDOMExternalizer;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.ui.GuiUtils;
import com.intellij.util.xmlb.XmlSerializerUtil;
import org.apache.commons.codec.binary.Base64;
import org.jdom.Element;
import org.jetbrains.annotations.Nls;
import javax.swing.*;
import java.io.IOException;
@@ -39,7 +35,13 @@ import java.net.*;
* Time: 3:58:23 PM
* To change this template use Options | File Templates.
*/
public class HttpConfigurable implements JDOMExternalizable, ApplicationComponent, SearchableConfigurable {
@State(
name = "HttpConfigurable",
storages = {
@Storage(id = "other", file = "$APP_CONFIG$/other.xml")
}
)
public class HttpConfigurable implements PersistentStateComponent<HttpConfigurable> {
public boolean USE_HTTP_PROXY = false;
public String PROXY_HOST = "";
public int PROXY_PORT = 80;
@@ -49,39 +51,33 @@ public class HttpConfigurable implements JDOMExternalizable, ApplicationComponen
public String PROXY_PASSWORD_CRYPT = "";
public boolean KEEP_PROXY_PASSWORD = false;
private HTTPProxySettingsPanel myPanel;
public static HttpConfigurable getInstance() {
return ServiceManager.getService(HttpConfigurable.class);
}
public void readExternal(Element element) throws InvalidDataException {
DefaultJDOMExternalizer.readExternal(this, element);
if (!KEEP_PROXY_PASSWORD)
public static boolean editConfigurable(final JComponent parent) {
return ShowSettingsUtil.getInstance().editConfigurable(parent, new HTTPProxySettingsPanel(getInstance()));
}
@Override
public HttpConfigurable getState() {
final HttpConfigurable state = new HttpConfigurable();
XmlSerializerUtil.copyBean(this, state);
if (!KEEP_PROXY_PASSWORD) {
state.PROXY_PASSWORD_CRYPT = "";
}
return state;
}
@Override
public void loadState(HttpConfigurable state) {
XmlSerializerUtil.copyBean(state, this);
if (!KEEP_PROXY_PASSWORD) {
PROXY_PASSWORD_CRYPT = "";
}
}
public void writeExternal(Element element) throws WriteExternalException {
String proxyPassword = PROXY_PASSWORD_CRYPT;
if (!KEEP_PROXY_PASSWORD)
PROXY_PASSWORD_CRYPT = "";
DefaultJDOMExternalizer.writeExternal(this, element);
PROXY_PASSWORD_CRYPT = proxyPassword;
}
public String getComponentName() {
return "HttpConfigurable";
}
public void initComponent() {
}
public void disposeComponent() {
}
public String getPlainProxyPassword () {
public String getPlainProxyPassword() {
return new String(new Base64().decode(PROXY_PASSWORD_CRYPT.getBytes()));
}
@@ -90,8 +86,7 @@ public class HttpConfigurable implements JDOMExternalizable, ApplicationComponen
}
public PasswordAuthentication getPromptedAuthentication(final String host, final String prompt) {
if (PROXY_AUTHENTICATION &&
! KEEP_PROXY_PASSWORD) {
if (PROXY_AUTHENTICATION && !KEEP_PROXY_PASSWORD) {
Runnable runnable = new Runnable() {
public void run() {
AuthenticationDialog dlg = new AuthenticationDialog(host, prompt);
@@ -158,52 +153,4 @@ public class HttpConfigurable implements JDOMExternalizable, ApplicationComponen
Authenticator.setDefault(null);
}
}
public String getId() {
return getHelpTopic();
}
public Runnable enableSearch(final String option) {
return null;
}
@Nls
public String getDisplayName() {
return "HTTP Proxy";
}
public Icon getIcon() {
return null;
}
public String getHelpTopic() {
return "http.proxy";
}
public JComponent createComponent() {
if (myPanel == null) {
myPanel = new HTTPProxySettingsPanel(getInstance());
}
return myPanel.getComponent();
}
public boolean isModified() {
return myPanel != null && myPanel.isModified();
}
public void apply() throws ConfigurationException {
if (myPanel != null) {
myPanel.apply();
}
}
public void reset() {
if (myPanel != null) {
myPanel.reset();
}
}
public void disposeUIResources() {
myPanel = null;
}
}
@@ -229,14 +229,14 @@ public final class LocalFileSystemImpl extends LocalFileSystemBase implements Ap
}
}
public void markSuspicousFilesDirty(List<VirtualFile> files) {
public void markSuspiciousFilesDirty(List<VirtualFile> files) {
storeRefreshStatusToFiles();
if (myWatcher.isOperational()) {
for (String root : myWatcher.getManualWatchRoots()) {
final VirtualFile suspicousRoot = findFileByPathIfCached(root);
if (suspicousRoot != null) {
((NewVirtualFile)suspicousRoot).markDirtyRecursively();
final VirtualFile suspiciousRoot = findFileByPathIfCached(root);
if (suspiciousRoot != null) {
((NewVirtualFile)suspiciousRoot).markDirtyRecursively();
}
}
}
@@ -45,9 +45,8 @@ public class RefreshSessionImpl extends RefreshSession {
private final Semaphore mySemaphore = new Semaphore();
private volatile boolean iHaveEventsToFire;
public RefreshSessionImpl(final boolean isAsync, boolean reqursively,
final Runnable finishRunnable) {
myIsRecursive = reqursively;
public RefreshSessionImpl(final boolean isAsync, final boolean recursively, final Runnable finishRunnable) {
myIsRecursive = recursively;
myFinishRunnable = finishRunnable;
myIsAsync = isAsync;
}
@@ -83,7 +82,7 @@ public class RefreshSessionImpl extends RefreshSession {
boolean hasEventsToFire = myFinishRunnable != null || !myEvents.isEmpty();
if (!workQueue.isEmpty()) {
((LocalFileSystemImpl)LocalFileSystem.getInstance()).markSuspicousFilesDirty(workQueue);
((LocalFileSystemImpl)LocalFileSystem.getInstance()).markSuspiciousFilesDirty(workQueue);
for (VirtualFile file : workQueue) {
final NewVirtualFile nvf = (NewVirtualFile)file;
@@ -176,7 +176,7 @@
<!-- Plugins -->
<applicationConfigurable instance="com.intellij.ide.plugins.PluginManagerConfigurable"/>
<applicationConfigurable implementation="com.intellij.util.net.HttpConfigurable"/>
<applicationConfigurable instance="com.intellij.util.net.HTTPProxySettingsPanel"/>
<applicationConfigurable instance="com.intellij.openapi.diff.impl.external.DiffOptionsForm"/>
<fileTypeFactory implementation="com.intellij.openapi.fileTypes.impl.PlatformFileTypeFactory"/>
@@ -305,6 +305,7 @@ public class StringUtil {
}
else if (c == '\r') {
if (i + 1 < text.length() && text.charAt(i + 1) == '\n') {
//noinspection AssignmentToForLoopParameter
i++;
count++;
}
@@ -316,6 +317,14 @@ public class StringUtil {
return count;
}
public static boolean containsLineBreak(@NotNull CharSequence text) {
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
if (c == '\n' || c == '\r') return true;
}
return false;
}
public static int lineColToOffset(@NotNull CharSequence text, int line, int col) {
int curLine = 0;
int offset = 0;
@@ -41,7 +41,7 @@ public class VcsGuess {
@Nullable
public AbstractVcs getVcsForDirty(final VirtualFile file) {
if (!file.isInLocalFileSystem()) {
if (!file.isInLocalFileSystem() || myExcludedFileIndex == null) {
return null;
}
if (myExcludedFileIndex.isInContent(file) || isFileInBaseDir(file) ||
@@ -20,6 +20,7 @@ import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.GuiUtils;
import com.intellij.util.containers.HashMap;
import com.intellij.vcsUtil.VcsUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -28,10 +29,13 @@ import org.zmlx.hg4idea.command.HgWorkingCopyRevisionsCommand;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* <strong><font color="#FF0000">TODO JavaDoc.</font></strong>
* HgUtil is a collection of static utility methods for Mercurial.
*/
public abstract class HgUtil {
@@ -197,6 +201,9 @@ public abstract class HgUtil {
*/
@Nullable
public static VirtualFile getHgRootOrNull(Project project, FilePath filePath) {
if (project == null) {
return getNearestHgRoot(VcsUtil.getVirtualFile(filePath.getPath()));
}
return getNearestHgRoot(VcsUtil.getVcsRootFor(project, filePath));
}
@@ -225,14 +232,9 @@ public abstract class HgUtil {
return vf;
}
/**
* Gets the Mercurial root for the given file or throws a VcsException if non exists:
* the root should not only be in directory mappings, but also the .hg repository folder should exist.
* @see #getHgRootOrNull(com.intellij.openapi.project.Project, com.intellij.openapi.vcs.FilePath)
*/
@NotNull
public static VirtualFile getHgRootOrThrow(Project project, VirtualFile vf) throws VcsException {
return getHgRootOrThrow(project, VcsUtil.getFilePath(vf.getPath()));
public static VirtualFile getHgRootOrThrow(Project project, VirtualFile file) throws VcsException {
return getHgRootOrThrow(project, VcsUtil.getFilePath(file.getPath()));
}
/**
@@ -246,5 +248,26 @@ public abstract class HgUtil {
public static boolean isMergeInProgress(@NotNull Project project, VirtualFile repository) {
return new HgWorkingCopyRevisionsCommand(project).parents(repository).size() > 1;
}
/**
* Groups the given files by their Mercurial repositories and returns the map of relative paths to files for each repository.
* @param hgFiles files to be grouped.
* @return key is repository, values is the non-empty list of relative paths to files, which belong to this repository.
*/
@NotNull
public static Map<VirtualFile, List<String>> getRelativePathsByRepository(Collection<HgFile> hgFiles) {
final Map<VirtualFile, List<String>> map = new HashMap<VirtualFile, List<String>>();
if (hgFiles == null) {
return map;
}
for(HgFile file : hgFiles) {
final VirtualFile repo = file.getRepo();
List<String> files = map.get(repo);
if (files == null) {
files = new ArrayList<String>();
map.put(repo, files);
}
files.add(file.getRelativePath());
}
return map;
}
}
@@ -15,6 +15,8 @@
*/
package org.zmlx.hg4idea;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vcs.changes.ChangeListManagerImpl;
@@ -22,6 +24,7 @@ import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ui.VcsBackgroundTask;
import com.intellij.vcsUtil.VcsUtil;
import org.jetbrains.annotations.NotNull;
import org.zmlx.hg4idea.command.*;
import java.util.*;
@@ -82,24 +85,45 @@ public class HgVFSListener extends VcsVFSListener {
}
@Override
protected void performAdding(Collection<VirtualFile> addedFiles, final Map<VirtualFile, VirtualFile> copyFromMap) {
(new VcsBackgroundTask<VirtualFile>(myProject,
HgVcsMessages.message("hg4idea.add.progress"),
VcsConfiguration.getInstance(myProject).getAddRemoveOption(),
addedFiles) {
protected void process(final VirtualFile file) throws VcsException {
if (file.isDirectory()) {
return;
}
final VirtualFile copyFrom = copyFromMap.get(file);
if (copyFrom != null) {
(new HgCopyCommand(myProject)).execute(new HgFile(myProject, copyFrom), new HgFile(myProject, file));
} else {
(new HgAddCommand(myProject)).execute(new HgFile(myProject, file));
}
dirtyScopeManager.fileDirty(file);
}
protected void performAdding(final Collection<VirtualFile> addedFiles, final Map<VirtualFile, VirtualFile> copyFromMap) {
(new Task.ConditionalModal(myProject,
HgVcsMessages.message("hg4idea.add.progress"),
false,
VcsConfiguration.getInstance(myProject).getAddRemoveOption() ) {
@Override public void run(@NotNull ProgressIndicator aProgressIndicator) {
final ArrayList<HgFile> adds = new ArrayList<HgFile>();
final HashMap<HgFile, HgFile> copies = new HashMap<HgFile, HgFile>(); // from -> to
// separate adds from copies
for (VirtualFile file : addedFiles) {
if (file.isDirectory()) {
continue;
}
final VirtualFile copyFrom = copyFromMap.get(file);
if (copyFrom != null) {
copies.put(new HgFile(myProject, copyFrom), new HgFile(myProject, file));
} else {
adds.add(new HgFile(myProject, file));
}
}
// add for all files at once
if (!adds.isEmpty()) {
new HgAddCommand(myProject).execute(adds);
}
// copy needs to be run for each file separately
if (!copies.isEmpty()) {
for(Map.Entry<HgFile, HgFile> copy : copies.entrySet()) {
new HgCopyCommand(myProject).execute(copy.getKey(), copy.getValue());
}
}
for (VirtualFile file : addedFiles) {
dirtyScopeManager.fileDirty(file);
}
}
}).queue();
}
@@ -118,6 +142,29 @@ public class HgVFSListener extends VcsVFSListener {
return HgVcsMessages.message("hg4idea.remove.single.body");
}
@Override
protected VcsDeleteType needConfirmDeletion(VirtualFile file) {
//// newly added files (which were added to the repo but never committed) should be removed from the VCS,
//// but without user confirmation.
final FilePath filePath = VcsUtil.getFilePath(file.getPath());
final VirtualFile repo = HgUtil.getHgRootOrNull(myProject, filePath);
if (repo == null) {
return super.needConfirmDeletion(file);
}
final HgFile hgFile = new HgFile(repo, filePath);
final HgLogCommand logCommand = new HgLogCommand(myProject);
logCommand.setLogFile(true);
logCommand.setFollowCopies(false);
logCommand.setIncludeRemoved(true);
final List<HgFileRevision> localRevisions = logCommand.execute(hgFile, -1, true);
// file is newly added, if it doesn't have a history or if the last history action was deleting this file.
if (localRevisions == null || localRevisions.isEmpty() || localRevisions.get(0).getDeletedFiles().contains(hgFile.getRelativePath())) {
return VcsDeleteType.SILENT;
}
return VcsDeleteType.CONFIRM;
}
protected void executeDelete() {
final List<FilePath> filesToDelete = new ArrayList<FilePath>(myDeletedWithoutConfirmFiles);
final List<FilePath> deletedFiles = new ArrayList<FilePath>(myDeletedFiles);
@@ -125,33 +172,9 @@ public class HgVFSListener extends VcsVFSListener {
myDeletedFiles.clear();
// skip unversioned files and files which are not under Mercurial
final List<FilePath> unversionedFilePaths = new ArrayList<FilePath>();
for (VirtualFile vf : ChangeListManagerImpl.getInstanceImpl(myProject).getUnversionedFiles()) {
unversionedFilePaths.add(VcsUtil.getFilePath(vf.getPath()));
}
skipUnversionedAndNotUnderHg(unversionedFilePaths, filesToDelete);
skipUnversionedAndNotUnderHg(unversionedFilePaths, deletedFiles);
// newly added files (which were added to the repo but never committed should be removed from the VCS,
// but without user confirmation.
for (Iterator<FilePath> it = deletedFiles.iterator(); it.hasNext(); ) {
final FilePath filePath = it.next();
final HgLogCommand logCommand = new HgLogCommand(myProject);
logCommand.setLogFile(true);
logCommand.setFollowCopies(false);
logCommand.setIncludeRemoved(true);
final VirtualFile repo = HgUtil.getHgRootOrNull(myProject, filePath);
if (repo == null) {
continue;
}
final HgFile hgFile = new HgFile(repo, filePath);
final List<HgFileRevision> localRevisions = logCommand.execute(hgFile, -1, true);
// file is newly added, if it doesn't have a history or if the last history action was deleting this file.
if (localRevisions == null || localRevisions.isEmpty() || localRevisions.get(0).getDeletedFiles().contains(hgFile.getRelativePath())) {
it.remove();
filesToDelete.add(filePath);
}
}
final ChangeListManagerImpl changeListManager = ChangeListManagerImpl.getInstanceImpl(myProject);
skipUnversionedAndNotUnderHg(changeListManager, filesToDelete);
skipUnversionedAndNotUnderHg(changeListManager, deletedFiles);
// confirm removal from the VCS if needed
if (myRemoveOption.getValue() != VcsShowConfirmationOption.Value.DO_NOTHING_SILENTLY) {
@@ -172,34 +195,43 @@ public class HgVFSListener extends VcsVFSListener {
}
/**
* Changes the given collection of files by filtering out unversioned files,
* files which are not under Mercurial repository, and
* newly added files (which were added to the repo, but never committed).
* @param unversionedFiles unversioned files retrieved from the ChangeListManager.
* Passing as a parameter not to transform List<VirtualFile> to List<FilePath> twice.
* Changes the given collection of files by filtering out unversioned files and
* files which are not under Mercurial repository.
* @param changeListManager instance of the ChangeListManagerImpl to retrieve unversioned files from it.
* @param filesToFilter files to be filtered.
*/
private void skipUnversionedAndNotUnderHg(Collection<FilePath> unversionedFiles, Collection<FilePath> filesToFilter) {
private void skipUnversionedAndNotUnderHg(ChangeListManagerImpl changeListManager, Collection<FilePath> filesToFilter) {
for (Iterator<FilePath> iter = filesToFilter.iterator(); iter.hasNext(); ) {
final FilePath filePath = iter.next();
if (HgUtil.getHgRootOrNull(myProject, filePath) == null || unversionedFiles.contains(filePath)) {
if (HgUtil.getHgRootOrNull(myProject, filePath) == null || changeListManager.isUnversioned(filePath.getVirtualFile())) {
iter.remove();
}
}
}
@Override
protected void performDeletion(List<FilePath> filesToDelete) {
(new VcsBackgroundTask<FilePath>(myProject,
protected void performDeletion( final List<FilePath> filesToDelete) {
(new Task.ConditionalModal(myProject,
HgVcsMessages.message("hg4idea.remove.progress"),
VcsConfiguration.getInstance(myProject).getAddRemoveOption(),
filesToDelete) {
protected void process(final FilePath file) throws VcsException {
if (file.isDirectory()) {
return;
false,
VcsConfiguration.getInstance(myProject).getAddRemoveOption()) {
@Override public void run( @NotNull ProgressIndicator aProgressIndicator ) {
final ArrayList<HgFile> deletes = new ArrayList<HgFile>();
for (FilePath file : filesToDelete) {
if (file.isDirectory()) {
continue;
}
deletes.add(new HgFile(VcsUtil.getVcsRootFor(myProject, file), file));
}
if (!deletes.isEmpty()) {
new HgRemoveCommand(myProject).execute(deletes);
}
for (HgFile file : deletes) {
dirtyScopeManager.fileDirty(file.toFilePath());
}
(new HgRemoveCommand(myProject)).execute(new HgFile(VcsUtil.getVcsRootFor(myProject, file), file));
dirtyScopeManager.fileDirty(file);
}
}).queue();
@@ -13,22 +13,43 @@
package org.zmlx.hg4idea.command;
import com.intellij.openapi.project.Project;
import org.zmlx.hg4idea.HgFile;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.zmlx.hg4idea.HgFile;
import org.zmlx.hg4idea.HgUtil;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* A wrapper for 'hg add' command.
*/
public class HgAddCommand {
private final Project project;
private final Project myProject;
public HgAddCommand(Project project) {
this.project = project;
myProject = project;
}
public void execute(@NotNull HgFile hgFile) {
HgCommandService.getInstance(project)
.execute(hgFile.getRepo(), "add", Arrays.asList(hgFile.getRelativePath()));
/**
* Adds given files to their Mercurial repositories.
* @param hgFiles files to be added.
*/
public void execute(@NotNull HgFile... hgFiles) {
execute(Arrays.asList(hgFiles));
}
/**
* Adds given files to their Mercurial repositories.
* @param hgFiles files to be added.
*/
public void execute(@NotNull Collection<HgFile> hgFiles) {
for(Map.Entry<VirtualFile, List<String>> entry : HgUtil.getRelativePathsByRepository(hgFiles).entrySet()) {
HgCommandService.getInstance(myProject).execute(entry.getKey(), "add", entry.getValue());
}
}
}
@@ -13,21 +13,45 @@
package org.zmlx.hg4idea.command;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.zmlx.hg4idea.HgFile;
import org.zmlx.hg4idea.HgUtil;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* A wrapper for the 'hg remove' command.
*/
public class HgRemoveCommand {
private final Project project;
private final Project myProject;
public HgRemoveCommand(Project project) {
this.project = project;
myProject = project;
}
public void execute(HgFile hgFile) {
HgCommandService.getInstance(project)
.execute(hgFile.getRepo(), "remove", Arrays.asList("--after", hgFile.getRelativePath()));
/**
* Removes given files from their Mercurial repositories.
* @param hgFiles files to be removed.
*/
public void execute(@NotNull HgFile... hgFiles) {
execute(Arrays.asList(hgFiles));
}
/**
* Removes given files from their Mercurial repositories.
* @param hgFiles files to be removed.
*/
public void execute(@NotNull Collection<HgFile> hgFiles) {
for( Map.Entry<VirtualFile, List<String>> entry : HgUtil.getRelativePathsByRepository(hgFiles).entrySet()) {
List<String> filePaths = entry.getValue();
filePaths.add(0, "--after");
HgCommandService.getInstance(myProject).execute(entry.getKey(), "remove", filePaths);
}
}
}
@@ -14,6 +14,7 @@ package org.zmlx.hg4idea.test;
import com.intellij.execution.process.ProcessOutput;
import com.intellij.openapi.application.PluginPathManager;
import com.intellij.openapi.vcs.AbstractVcsHelper;
import com.intellij.openapi.vcs.VcsConfiguration;
import com.intellij.openapi.vcs.VcsShowConfirmationOption;
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
@@ -22,6 +23,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.testFramework.AbstractVcsTestCase;
import com.intellij.vcsUtil.VcsUtil;
import org.jetbrains.annotations.Nullable;
import org.picocontainer.MutablePicoContainer;
import org.testng.annotations.BeforeMethod;
import org.zmlx.hg4idea.HgFile;
import org.zmlx.hg4idea.HgVcs;
@@ -64,14 +66,18 @@ public abstract class HgAbstractTestCase extends AbstractVcsTestCase {
myTraceClient = true;
}
protected void enableSilentOperation(final VcsConfiguration.StandardConfirmation op) {
protected void doActionSilently(final VcsConfiguration.StandardConfirmation op) {
setStandardConfirmation(HgVcs.VCS_NAME, op, VcsShowConfirmationOption.Value.DO_ACTION_SILENTLY);
}
protected void disableSilentOperation(final VcsConfiguration.StandardConfirmation op) {
protected void doNothingSilently(final VcsConfiguration.StandardConfirmation op) {
setStandardConfirmation(HgVcs.VCS_NAME, op, VcsShowConfirmationOption.Value.DO_NOTHING_SILENTLY);
}
protected void showConfirmation(final VcsConfiguration.StandardConfirmation op) {
setStandardConfirmation(HgVcs.VCS_NAME, op, VcsShowConfirmationOption.Value.SHOW_CONFIRMATION);
}
/**
* Runs the hg command.
*
@@ -111,8 +117,17 @@ public abstract class HgAbstractTestCase extends AbstractVcsTestCase {
}
return new HgFile(myWorkingCopyDir, fileToInclude);
}
/**
* Registers HgMockVcsHelper as the AbstractVcsHelper.
*/
protected HgMockVcsHelper registerMockVcsHelper() {
final String key = "com.intellij.openapi.vcs.AbstractVcsHelper";
final MutablePicoContainer picoContainer = (MutablePicoContainer) myProject.getPicoContainer();
picoContainer.unregisterComponent(key);
picoContainer.registerComponentImplementation(key, HgMockVcsHelper.class);
return (HgMockVcsHelper) AbstractVcsHelper.getInstance(myProject);
}
protected VirtualFile makeFile(File file) throws IOException {
file.createNewFile();
@@ -45,8 +45,8 @@ public class HgCollaborativeTestCase extends HgAbstractTestCase {
activateVCS(HgVcs.VCS_NAME);
myChangeListManager = new HgTestChangeListManager(myProject);
enableSilentOperation(VcsConfiguration.StandardConfirmation.ADD);
enableSilentOperation(VcsConfiguration.StandardConfirmation.REMOVE);
doActionSilently(VcsConfiguration.StandardConfirmation.ADD);
doActionSilently(VcsConfiguration.StandardConfirmation.REMOVE);
}
}
@@ -12,12 +12,15 @@
// limitations under the License.
package org.zmlx.hg4idea.test;
import com.intellij.openapi.vcs.VcsConfiguration;
import com.intellij.openapi.vfs.VirtualFile;
import org.testng.Assert;
import org.testng.annotations.Test;
import java.io.File;
import static org.testng.Assert.fail;
public class HgDeleteTestCase extends HgSingleUserTestCase {
@Test
@@ -62,4 +65,51 @@ public class HgDeleteTestCase extends HgSingleUserTestCase {
verify(runHgOnProjectRepo("status"), HgTestOutputParser.removed("com", "a.txt"));
}
/**
* When deleting a file which was newly added to repository, this file shouldn't be prompted for removal from the repository.
* 1. Create a file and add it to the repository.
* 2. Remove the file from disk.
* 3. File shouldn't be prompted for removal from repository.
*/
@Test
public void testNewlyAddedFileShouldNotBePromptedForRemoval() throws Exception {
showConfirmation(VcsConfiguration.StandardConfirmation.REMOVE);
final VirtualFile vf = createFileInCommand("a.txt", null);
final HgMockVcsHelper helper = registerMockVcsHelper();
helper.addListener(new VcsHelperListener() {
@Override
public void dialogInvoked() {
fail("No dialog should be invoked, because newly added file should be silently removed from the repository");
}
});
deleteFileInCommand(vf);
}
/**
* A file is also considered to be newly added, if it has a history, but the last action was removal of that file.
* 1. Create a file, add it to the repository and commit.
* 2. Delete the file and commit it.
* 3. Create the file again and add it to the repository.
* 4. Delete the file.
* 5. File shouldn't be prompted for removal from repository.
*/
@Test
public void testJustDeletedAndThenAddedFileShouldNotBePromptedForRemoval() throws Exception {
VirtualFile vf = createFileInCommand("a.txt", null);
myChangeListManager.commitFiles(vf);
deleteFileInCommand(vf);
myChangeListManager.commitFiles(vf);
showConfirmation(VcsConfiguration.StandardConfirmation.REMOVE);
vf = createFileInCommand("a.txt", null);
final HgMockVcsHelper helper = registerMockVcsHelper();
helper.addListener(new VcsHelperListener() {
@Override
public void dialogInvoked() {
fail("No dialog should be invoked, because newly added file should be silently removed from the repository");
}
});
deleteFileInCommand(myProject, vf);
}
}
@@ -0,0 +1,174 @@
/*
* 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 org.zmlx.hg4idea.test;
import com.intellij.ide.errorTreeView.HotfixData;
import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vcs.annotate.AnnotationProvider;
import com.intellij.openapi.vcs.annotate.FileAnnotation;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.history.VcsFileRevision;
import com.intellij.openapi.vcs.history.VcsHistoryProvider;
import com.intellij.openapi.vcs.merge.MergeProvider;
import com.intellij.openapi.vcs.versionBrowser.ChangeBrowserSettings;
import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
import com.intellij.openapi.vfs.VirtualFile;
import gnu.trove.THashSet;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.io.File;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* Substitutes AbstractVcsHelperImpl for tests, where dialogs need to be tested.
* Currently it's just a stub implementation notifying listeners about action invoked (which would mean than a dialog would have been
* shown during normal execution).
* @author Kirill Likhodedov
*/
public class HgMockVcsHelper extends AbstractVcsHelper {
private Collection<VcsHelperListener> myListeners = new THashSet<VcsHelperListener>();
@Override
public void showErrors(List<VcsException> abstractVcsExceptions, @NotNull String tabDisplayName) {
}
@Override
public void showErrors(Map<HotfixData, List<VcsException>> exceptionGroups, @NotNull String tabDisplayName) {
}
@Override
public List<VcsException> runTransactionRunnable(AbstractVcs vcs, TransactionRunnable runnable, Object vcsParameters) {
return null;
}
@Override
public void showAnnotation(FileAnnotation annotation, VirtualFile file, AbstractVcs vcs) {
}
@Override
public void showDifferences(VcsFileRevision cvsVersionOn, VcsFileRevision cvsVersionOn1, File file) {
}
@Override
public void showChangesListBrowser(CommittedChangeList changelist, @Nls String title) {
}
@Override
public void showChangesBrowser(List<CommittedChangeList> changelists) {
}
@Override
public void showChangesBrowser(List<CommittedChangeList> changelists, @Nls String title) {
}
@Override
public void showChangesBrowser(CommittedChangesProvider provider,
RepositoryLocation location,
@Nls String title,
@Nullable Component parent) {
}
@Override
public void showWhatDiffersBrowser(@Nullable Component parent, Collection<Change> changes, @Nls String title) {
}
@Override
public <T extends CommittedChangeList, U extends ChangeBrowserSettings> T chooseCommittedChangeList(CommittedChangesProvider<T, U> provider,
RepositoryLocation location) {
return null;
}
@Override
public void openCommittedChangesTab(AbstractVcs vcs, VirtualFile root, ChangeBrowserSettings settings, int maxCount, String title) {
}
@Override
public void openCommittedChangesTab(CommittedChangesProvider provider,
RepositoryLocation location,
ChangeBrowserSettings settings,
int maxCount,
String title) {
}
@NotNull
@Override
public List<VirtualFile> showMergeDialog(List<VirtualFile> files, MergeProvider provider) {
return null;
}
@NotNull
@Override
public List<VirtualFile> showMergeDialog(List<VirtualFile> files) {
return null;
}
@Override
public void showFileHistory(VcsHistoryProvider vcsHistoryProvider, FilePath path, AbstractVcs vcs, String repositoryPath) {
}
@Override
public void showFileHistory(VcsHistoryProvider vcsHistoryProvider,
AnnotationProvider annotationProvider,
FilePath path,
String repositoryPath,
AbstractVcs vcs) {
}
@Override
public void showRollbackChangesDialog(List<Change> changes) {
}
@Nullable
@Override
public Collection<VirtualFile> selectFilesToProcess(List<VirtualFile> files,
String title,
@Nullable String prompt,
String singleFileTitle,
String singleFilePromptTemplate,
VcsShowConfirmationOption confirmationOption) {
notifyListeners();
return null;
}
@Nullable
@Override
public Collection<FilePath> selectFilePathsToProcess(List<FilePath> files,
String title,
@Nullable String prompt,
String singleFileTitle,
String singleFilePromptTemplate,
VcsShowConfirmationOption confirmationOption) {
notifyListeners();
return null;
}
public void addListener(VcsHelperListener listener) {
myListeners.add(listener);
}
private void notifyListeners() {
for (VcsHelperListener listener : myListeners) {
listener.dialogInvoked();
}
}
}
@@ -42,8 +42,8 @@ public class HgSingleUserTestCase extends HgAbstractTestCase {
activateVCS(HgVcs.VCS_NAME);
myChangeListManager = new HgTestChangeListManager(myProject);
enableSilentOperation(VcsConfiguration.StandardConfirmation.ADD);
enableSilentOperation(VcsConfiguration.StandardConfirmation.REMOVE);
doActionSilently(VcsConfiguration.StandardConfirmation.ADD);
doActionSilently(VcsConfiguration.StandardConfirmation.REMOVE);
}
}
@@ -24,7 +24,6 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.HashSet;
import org.testng.Assert;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -50,6 +49,7 @@ public class HgTestChangeListManager {
*/
public void addUnversionedFilesToVcs(VirtualFile... files) {
peer.addUnversionedFiles(peer.getDefaultChangeList(), Arrays.asList(files));
ensureUpToDate();
}
/**
@@ -59,7 +59,7 @@ public class HgTestChangeListManager {
* @param files Files to be checked.
*/
public void checkFilesAreInList(boolean only, VirtualFile... files) {
peer.ensureUpToDate(false);
ensureUpToDate();
final Collection<Change> changes = peer.getDefaultChangeList().getChanges();
if (only) {
@@ -78,6 +78,7 @@ public class HgTestChangeListManager {
* Commits all changes of the given files.
*/
public void commitFiles(VirtualFile... files) {
ensureUpToDate();
final List<Change> changes = new ArrayList<Change>(files.length);
for (VirtualFile f : files) {
changes.addAll(peer.getChangesIn(f));
@@ -86,20 +87,17 @@ public class HgTestChangeListManager {
assertNotNull(list);
list.setComment("A comment to a commit");
Assert.assertTrue(peer.commitChangesSynchronouslyWithResult(list, changes));
ensureUpToDate();
}
public void removeFiles(final VirtualFile file) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
try {
file.delete(this);
}
catch (IOException e) {
e.printStackTrace();
}
}
});
/**
* Ensures the ChangelistManager is up to date.
* It is called after each operation in the HgTestChangeListManager.
*/
public void ensureUpToDate() {
if (!ApplicationManager.getApplication().isDispatchThread()) { // for dispatch thread no need to force update.
peer.ensureUpToDate(false);
}
}
}
@@ -0,0 +1,24 @@
/*
* 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 org.zmlx.hg4idea.test;
/**
* Listens to events in HgMockVcsHelper.
* @author Kirill Likhodedov
*/
public interface VcsHelperListener {
void dialogInvoked();
}
+6 -2
View File
@@ -404,10 +404,14 @@
<projectService serviceInterface="com.intellij.openapi.vcs.CodeSmellDetector"
serviceImplementation="com.intellij.openapi.vcs.impl.CodeSmellDetectorImpl"/>
<projectService serviceInterface="com.intellij.openapi.vcs.changes.patch.PatchBaseDirectoryDetector"
serviceImplementation="com.intellij.openapi.vcs.changes.patch.PsiPatchBaseDirectoryDetector"/>
<projectService serviceInterface="com.intellij.openapi.vcs.changes.ui.ChangesGroupingPolicyFactory"
serviceImplementation="com.intellij.openapi.vcs.changes.ui.ChangesModuleGroupingPolicyFactory"/>
<projectService serviceInterface="com.intellij.openapi.vcs.impl.DefaultVcsRootPolicy"
serviceImplementation="com.intellij.openapi.vcs.impl.ModuleDefaultVcsRootPolicy"/>
<projectService serviceInterface="com.intellij.openapi.vcs.impl.ExcludedFileIndex"
serviceImplementation="com.intellij.openapi.vcs.impl.ProjectExcludedFileIndex"/>
<projectService serviceInterface="com.intellij.openapi.vcs.impl.VcsPathPresenter"
serviceImplementation="com.intellij.openapi.vcs.impl.ModuleVcsPathPresenter"/>
@@ -644,9 +648,9 @@
<!-- Path Variables -->
<!-- the implementation of this configurable is in platform-impl but it's not registered in platform because
it's only required in full IDEA -->
<applicationConfigurable instance="com.intellij.application.options.pathMacros.PathMacroConfigurable"/>
<applicationConfigurable implementation="com.intellij.application.options.pathMacros.PathMacroConfigurable"/>
<applicationConfigurable instance="com.intellij.execution.console.ConsoleFoldingConfigurable"/>
<applicationConfigurable implementation="com.intellij.execution.console.ConsoleFoldingConfigurable"/>
<!-- Resources -->