mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'master' of git.labs.intellij.net:idea/community
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
+3
-1
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -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();
|
||||
}
|
||||
@@ -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 -->
|
||||
|
||||
|
||||
Reference in New Issue
Block a user