mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -5,3 +5,4 @@ IDC_WINLAUNCHER=__IDE-NAME___LAUNCHER
|
||||
IDS_PROPS_ENV_VAR=__IDE-NAME___PROPERTIES
|
||||
IDS_VM_OPTIONS_ENV_VAR=__IDE-NAME___VM_OPTIONS
|
||||
IDS_ERROR_LAUNCHING_APP=Error launching __IDE-NAME__
|
||||
IDS_VM_OPTIONS=-Didea.paths.selector=__PRODUCT_PATHS_SELECTOR__
|
||||
|
||||
@@ -6,3 +6,4 @@ IDC_WINLAUNCHER=__IDE-NAME___LAUNCHER
|
||||
IDS_PROPS_ENV_VAR=__IDE-NAME___PROPERTIES
|
||||
IDS_VM_OPTIONS_ENV_VAR=__IDE-NAME__64_VM_OPTIONS
|
||||
IDS_ERROR_LAUNCHING_APP=Error launching __IDE-NAME__
|
||||
IDS_VM_OPTIONS=-Didea.paths.selector=__PRODUCT_PATHS_SELECTOR__
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import org.jetbrains.jps.gant.LayoutInfo
|
||||
|
||||
import static org.jetbrains.jps.idea.IdeaProjectLoader.guessHome
|
||||
@@ -127,6 +128,10 @@ def layoutAll(Map args, String home, String out, Paths _paths = null, buildJps =
|
||||
def layouts = includeFile("$home/build/scripts/layouts.gant")
|
||||
LayoutInfo info = layouts.layoutFull(home, paths.distAll, null)
|
||||
layouts.layout_core(home, paths.artifacts_core)
|
||||
ant.zip(destfile: "${paths.artifacts}/intellij-core-${StringUtil.trimStart(args.buildNumber, "IC-")}.zip") {
|
||||
fileset(dir: paths.artifacts_core)
|
||||
}
|
||||
|
||||
notifyArtifactBuilt(paths.artifacts_core)
|
||||
if (buildJps) {
|
||||
layouts.layoutJps(home, paths.artifacts_jps, args.buildNumber, {})
|
||||
|
||||
@@ -25,6 +25,7 @@ def nsis_installer(pathsToInclude, stringsFile, pathsFile, outNamePrefix, includ
|
||||
ant.mkdir(dir: "$box/jre")
|
||||
requireProperty("jdk_bundled_win", "1.7")
|
||||
def jdk_bundled_version = p("jdk_bundled_win") == "1.8" ? "${home}/build/jdk/jdk8_redist.zip" : "${home}/build/jdk/jdk_redist.zip"
|
||||
getBundledJDK(new File("${home}/build/jdk/win"), "jdk"+ p("jdk_bundled_win"), "x32.zip", jdk_bundled_version)
|
||||
ant.unzip(dest: "$box/jre", src: "${jdk_bundled_version}")
|
||||
|
||||
ant.copy(todir: "$box/bin") {
|
||||
|
||||
+11
-10
@@ -754,17 +754,18 @@ private List<File> getChildren(File file) {
|
||||
return file.listFiles().sort { File f -> f.name.toLowerCase() }
|
||||
}
|
||||
|
||||
binding.setVariable("getCustomJDK", { File customJdkDir ->
|
||||
getChildren(customJdkDir).each {
|
||||
if (it.getName().endsWith(".tar.gz")) {
|
||||
def customJdkFileName = it.getAbsolutePath().substring(0, it.getAbsolutePath().length() - 3)
|
||||
if (new File(customJdkFileName).exists()){ ant.delete(file: customJdkFileName) }
|
||||
if (new File("${home}/build/jdk/custom_jdk_${buildNumber}.tar").exists()){
|
||||
ant.delete(file: "${home}/build/jdk/custom_jdk_${buildNumber}.tar")
|
||||
binding.setVariable("getBundledJDK", { File jdkDir, String prefix, String ext, String bundledJDKFileName ->
|
||||
getChildren(jdkDir).each {
|
||||
if (it.getName().startsWith(prefix) && it.getName().endsWith(ext)) {
|
||||
if (new File(bundledJDKFileName).exists()) { ant.delete(file: bundledJDKFileName) }
|
||||
def JdkFileName = it.getAbsolutePath()
|
||||
if (ext == ".tar.gz") {
|
||||
JdkFileName = JdkFileName.substring(0, JdkFileName.length() - 3)
|
||||
if (new File(JdkFileName).exists()) { ant.delete(file: JdkFileName) }
|
||||
ant.gunzip(src: it.getAbsolutePath())
|
||||
}
|
||||
ant.gunzip(src: it.getAbsolutePath())
|
||||
projectBuilder.info("customJdkFileName: " + customJdkFileName)
|
||||
ant.copy(file: customJdkFileName, tofile: "${home}/build/jdk/custom_jdk_${buildNumber}.tar")
|
||||
projectBuilder.info("JdkFileName: " + JdkFileName)
|
||||
ant.copy(file: JdkFileName, tofile: bundledJDKFileName)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -415,6 +415,9 @@ public class CompileDriver {
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ProcessCanceledException ignored) {
|
||||
compileContext.putUserDataIfAbsent(COMPILE_SERVER_BUILD_STATUS, ExitStatus.CANCELLED);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.error(e); // todo
|
||||
}
|
||||
@@ -480,7 +483,7 @@ public class CompileDriver {
|
||||
final Set<File> genSourceRoots = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
|
||||
final CompilerConfiguration config = CompilerConfiguration.getInstance(myProject);
|
||||
for (Module module : affectedModules) {
|
||||
if (config.getAnnotationProcessingConfiguration(module).isEnabled()) {
|
||||
if (!module.isDisposed() && config.getAnnotationProcessingConfiguration(module).isEnabled()) {
|
||||
final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module);
|
||||
if (path != null) {
|
||||
genSourceRoots.add(new File(path));
|
||||
|
||||
@@ -78,7 +78,7 @@ public class CompilerPathsEx extends CompilerPaths {
|
||||
public static String[] getOutputPaths(Module[] modules) {
|
||||
final Set<String> outputPaths = new OrderedSet<String>();
|
||||
for (Module module : modules) {
|
||||
final CompilerModuleExtension compilerModuleExtension = CompilerModuleExtension.getInstance(module);
|
||||
final CompilerModuleExtension compilerModuleExtension = !module.isDisposed()? CompilerModuleExtension.getInstance(module) : null;
|
||||
if (compilerModuleExtension == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -143,7 +143,7 @@ class DebuggerSteppingConfigurable implements ConfigurableUi<DebuggerSettings> {
|
||||
final JPanel evalFinallyPanel = new JPanel(new BorderLayout());
|
||||
evalFinallyPanel.add(box, BorderLayout.CENTER);
|
||||
evalFinallyPanel.add(new JLabel(DebuggerBundle.message("label.debugger.general.configurable.evaluate.finally.on.pop")), BorderLayout.WEST);
|
||||
panel.add(evalFinallyPanel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(4, cbLeftOffset, 0, 0), 0, 0));
|
||||
panel.add(evalFinallyPanel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(4, cbLeftOffset, 0, 0), 0, 0));
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
+1
-1
@@ -212,7 +212,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
|
||||
private void flushArrayElementsOnUnknownIndexAssignment(PsiExpression lExpr) {
|
||||
if (lExpr instanceof PsiArrayAccessExpression &&
|
||||
myFactory.createValue(lExpr) == null // check for unknown index, otherwise AssignInstruction will flush only that element
|
||||
!(myFactory.createValue(lExpr) instanceof DfaVariableValue) // check for unknown index, otherwise AssignInstruction will flush only that element
|
||||
) {
|
||||
DfaValue arrayVar = myFactory.createValue(((PsiArrayAccessExpression)lExpr).getArrayExpression());
|
||||
if (arrayVar instanceof DfaVariableValue) {
|
||||
|
||||
@@ -70,13 +70,6 @@ public class DfaPsiUtil {
|
||||
return Nullness.UNKNOWN;
|
||||
}
|
||||
|
||||
if (NullableNotNullManager.isNullable(owner)) {
|
||||
return Nullness.NULLABLE;
|
||||
}
|
||||
if (NullableNotNullManager.isNotNull(owner)) {
|
||||
return Nullness.NOT_NULL;
|
||||
}
|
||||
|
||||
if (resultType != null) {
|
||||
NullableNotNullManager nnn = NullableNotNullManager.getInstance(owner.getProject());
|
||||
for (PsiAnnotation annotation : resultType.getAnnotations()) {
|
||||
@@ -95,6 +88,13 @@ public class DfaPsiUtil {
|
||||
}
|
||||
}
|
||||
|
||||
if (NullableNotNullManager.isNullable(owner)) {
|
||||
return Nullness.NULLABLE;
|
||||
}
|
||||
if (NullableNotNullManager.isNotNull(owner)) {
|
||||
return Nullness.NOT_NULL;
|
||||
}
|
||||
|
||||
return Nullness.UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -74,7 +74,7 @@ public class StandardDataFlowRunner extends DataFlowRunner {
|
||||
}
|
||||
|
||||
PsiType returnType = method.getReturnType();
|
||||
return returnType != null && returnType.equalsToText(CommonClassNames.JAVA_LANG_VOID);
|
||||
return returnType != null && (returnType == PsiType.VOID || returnType.equalsToText(CommonClassNames.JAVA_LANG_VOID));
|
||||
}
|
||||
|
||||
public void onInstructionProducesCCE(Instruction instruction) {
|
||||
|
||||
+4
-2
@@ -70,6 +70,7 @@ public class DfaExpressionFactory {
|
||||
return getExpressionDfaValue(((PsiParenthesizedExpression)expression).getExpression());
|
||||
}
|
||||
|
||||
PsiType type = expression.getType();
|
||||
if (expression instanceof PsiArrayAccessExpression) {
|
||||
PsiExpression arrayExpression = ((PsiArrayAccessExpression)expression).getArrayExpression();
|
||||
DfaValue qualifier = getExpressionDfaValue(arrayExpression);
|
||||
@@ -79,7 +80,9 @@ public class DfaExpressionFactory {
|
||||
return myFactory.getVarFactory().createVariableValue(indexVar, expression.getType(), false, (DfaVariableValue)qualifier);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
if (type != null) {
|
||||
return myFactory.createTypeValue(type, DfaPsiUtil.getElementNullability(type, null));
|
||||
}
|
||||
}
|
||||
|
||||
if (expression instanceof PsiMethodCallExpression) {
|
||||
@@ -99,7 +102,6 @@ public class DfaExpressionFactory {
|
||||
}
|
||||
|
||||
final Object value = JavaConstantExpressionEvaluator.computeConstantExpression(expression, false);
|
||||
PsiType type = expression.getType();
|
||||
if (value != null && type != null) {
|
||||
if (value instanceof String) {
|
||||
return myFactory.createTypeValue(type, Nullness.NOT_NULL); // Non-null string literal.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -212,6 +212,7 @@ public class TargetElementUtil extends TargetElementUtilBase {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<PsiElement> getTargetCandidates(final PsiReference reference) {
|
||||
PsiElement parent = reference.getElement().getParent();
|
||||
|
||||
+27
-81
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.source.codeStyle.javadoc;
|
||||
|
||||
import com.intellij.codeInsight.javadoc.JavaDocUtil;
|
||||
import com.intellij.ide.highlighter.JavaFileType;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
@@ -31,9 +30,12 @@ import com.intellij.psi.impl.source.SourceTreeToPsiMap;
|
||||
import com.intellij.psi.javadoc.PsiDocComment;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.psi.impl.source.codeStyle.javadoc.JDParser.CommentInfo;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
@@ -63,47 +65,12 @@ public class CommentFormatter {
|
||||
if (!getSettings().ENABLE_JAVADOC_FORMATTING) return;
|
||||
|
||||
PsiElement psiElement = SourceTreeToPsiMap.treeElementToPsi(element);
|
||||
processElementComment(psiElement);
|
||||
}
|
||||
|
||||
private void processElementComment(@Nullable PsiElement psiElement) {
|
||||
if (psiElement instanceof PsiClass) {
|
||||
String newCommentText = formatClassComment((PsiClass)psiElement);
|
||||
replaceDocComment(newCommentText, (PsiDocCommentOwner)psiElement);
|
||||
}
|
||||
else if (psiElement instanceof PsiMethod) {
|
||||
String newCommentText = formatMethodComment((PsiMethod)psiElement);
|
||||
replaceDocComment(newCommentText, (PsiDocCommentOwner)psiElement);
|
||||
}
|
||||
else if (psiElement instanceof PsiField) {
|
||||
String newCommentText = formatFieldComment((PsiField)psiElement);
|
||||
replaceDocComment(newCommentText, (PsiDocCommentOwner)psiElement);
|
||||
}
|
||||
else if (psiElement instanceof PsiDocComment) {
|
||||
PsiDocComment comment = (PsiDocComment)psiElement;
|
||||
if (JavaDocUtil.isInsidePackageInfo(comment)) {
|
||||
String newCommentText = formatPackageComment(comment);
|
||||
replaceCommentText(newCommentText, comment);
|
||||
} else {
|
||||
processElementComment(psiElement.getParent());
|
||||
}
|
||||
if (psiElement != null) {
|
||||
getParser().formatCommentText(psiElement, this);
|
||||
}
|
||||
}
|
||||
|
||||
private String formatPackageComment(@NotNull PsiDocComment comment) {
|
||||
final String info = getCommentInfo(comment);
|
||||
if (info == null) return null;
|
||||
|
||||
JDComment jdComment = getParser().parse(info, new JDComment(this));
|
||||
return jdComment.generate("");
|
||||
}
|
||||
|
||||
private void replaceDocComment(@Nullable String newCommentText, @NotNull final PsiDocCommentOwner psiDocCommentOwner) {
|
||||
final PsiDocComment oldComment = psiDocCommentOwner.getDocComment();
|
||||
replaceCommentText(newCommentText, oldComment);
|
||||
}
|
||||
|
||||
private void replaceCommentText(@Nullable String newCommentText, @Nullable PsiDocComment oldComment) {
|
||||
public void replaceCommentText(@Nullable String newCommentText, @Nullable PsiDocComment oldComment) {
|
||||
if (newCommentText != null) newCommentText = stripSpaces(newCommentText);
|
||||
if (newCommentText == null || oldComment == null || newCommentText.equals(oldComment.getText())) {
|
||||
return;
|
||||
@@ -142,53 +109,22 @@ public class CommentFormatter {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String formatClassComment(@NotNull PsiClass psiClass) {
|
||||
final String info = getOrigCommentInfo(psiClass);
|
||||
if (info == null) return null;
|
||||
|
||||
JDComment comment = getParser().parse(info, new JDClassComment(this));
|
||||
return comment.generate(getIndent(psiClass));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String formatMethodComment(@NotNull PsiMethod psiMethod) {
|
||||
final String info = getOrigCommentInfo(psiMethod);
|
||||
if (info == null) return null;
|
||||
|
||||
JDComment comment = getParser().parse(info, new JDMethodComment(this));
|
||||
return comment.generate(getIndent(psiMethod));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String formatFieldComment(@NotNull PsiField psiField) {
|
||||
final String info = getOrigCommentInfo(psiField);
|
||||
if (info == null) return null;
|
||||
|
||||
JDComment comment = getParser().parse(info, new JDComment(this));
|
||||
return comment.generate(getIndent(psiField));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the original comment info of the specified element or null
|
||||
*
|
||||
* @param element the specified element
|
||||
* @return text chunk
|
||||
*/
|
||||
@Nullable
|
||||
private static String getOrigCommentInfo(PsiDocCommentOwner element) {
|
||||
public static CommentInfo getOrigCommentInfo(PsiDocCommentOwner element) {
|
||||
PsiElement e = element.getFirstChild();
|
||||
if (!(e instanceof PsiComment)) {
|
||||
//no comments for this element
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return getCommentInfo(((PsiComment)e));
|
||||
return getCommentInfo((PsiComment)e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getCommentInfo(PsiComment element) {
|
||||
public static CommentInfo getCommentInfo(PsiComment element) {
|
||||
String commentHeader = null;
|
||||
String commentFooter = null;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
PsiElement e = element;
|
||||
boolean first = true;
|
||||
@@ -201,11 +137,18 @@ public class CommentFormatter {
|
||||
sb.append(text.substring(2).trim());
|
||||
}
|
||||
else if (text.startsWith("/*")) {
|
||||
if (text.charAt(2) == '*') {
|
||||
text = text.substring(3, Math.max(3, text.length() - 2));
|
||||
int commentHeaderEndOffset = CharArrayUtil.shiftForward(text, 1, "*");
|
||||
int commentFooterStartOffset = CharArrayUtil.shiftBackward(text, text.length() - 2, "*");
|
||||
|
||||
if (commentHeaderEndOffset <= commentFooterStartOffset) {
|
||||
commentHeader = text.substring(0, commentHeaderEndOffset);
|
||||
commentFooter = text.substring(commentFooterStartOffset + 1);
|
||||
text = text.substring(commentHeaderEndOffset, commentFooterStartOffset + 1);
|
||||
}
|
||||
else {
|
||||
text = text.substring(2, Math.max(2, text.length() - 2));
|
||||
commentHeader = text.substring(0, commentHeaderEndOffset);
|
||||
text = "";
|
||||
commentFooter = "";
|
||||
}
|
||||
sb.append(text);
|
||||
}
|
||||
@@ -217,7 +160,7 @@ public class CommentFormatter {
|
||||
e = e.getNextSibling();
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
return new CommentInfo(commentHeader, sb.toString(), commentFooter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -226,6 +169,9 @@ public class CommentFormatter {
|
||||
* @return indentation size
|
||||
*/
|
||||
private int getIndentSpecial(@NotNull PsiElement element) {
|
||||
if (element instanceof PsiDocComment) {
|
||||
return 0;
|
||||
}
|
||||
LOG.assertTrue(element instanceof PsiClass ||
|
||||
element instanceof PsiField ||
|
||||
element instanceof PsiMethod);
|
||||
@@ -252,7 +198,7 @@ public class CommentFormatter {
|
||||
* @return indent which would be used for the given element when it's formatted according to the current code style settings
|
||||
*/
|
||||
@NotNull
|
||||
private String getIndent(@NotNull PsiElement element) {
|
||||
public String getIndent(@NotNull PsiElement element) {
|
||||
return StringUtil.repeatSymbol(' ', getIndentSpecial(element));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ public class JDComment {
|
||||
private String mySince;
|
||||
private String myDeprecated;
|
||||
private boolean myMultiLineComment;
|
||||
private String myFirstLine = "/**";
|
||||
private String myEndLine = "*/";
|
||||
|
||||
public JDComment(@NotNull CommentFormatter formatter) {
|
||||
myFormatter = formatter;
|
||||
@@ -128,13 +130,13 @@ public class JDComment {
|
||||
|| sb.indexOf("\n") != sb.length() - 1) // If comment has become multiline after formatting - it must be shown as multiline.
|
||||
// Last symbol is always '\n', so we need to check if there is one more LF symbol before it.
|
||||
{
|
||||
sb.insert(0, "/**\n");
|
||||
sb.insert(0, myFirstLine + '\n');
|
||||
sb.append(indent);
|
||||
} else {
|
||||
sb.replace(0, prefix.length(), "/** ");
|
||||
sb.deleteCharAt(sb.length()-1);
|
||||
}
|
||||
sb.append(" */");
|
||||
sb.append(' ').append(myEndLine);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
@@ -142,6 +144,14 @@ public class JDComment {
|
||||
protected void generateSpecial(@NotNull String prefix, @NotNull StringBuilder sb) {
|
||||
}
|
||||
|
||||
public void setFirstCommentLine(@NotNull String firstCommentLine) {
|
||||
myFirstLine = firstCommentLine;
|
||||
}
|
||||
|
||||
public void setLastCommentLine(@NotNull String lastCommentLine) {
|
||||
myEndLine = lastCommentLine;
|
||||
}
|
||||
|
||||
public void addSeeAlso(@NotNull String seeAlso) {
|
||||
if (mySeeAlsoList == null) {
|
||||
mySeeAlsoList = ContainerUtilRt.newArrayList();
|
||||
|
||||
@@ -19,7 +19,9 @@ import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.psi.javadoc.PsiDocComment;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -40,6 +42,8 @@ public class JDParser {
|
||||
private static final String P_START_TAG = "<p>";
|
||||
private static final String SELF_CLOSED_P_TAG = "<p/>";
|
||||
|
||||
private static final char lineSeparator = '\n';
|
||||
|
||||
private final CodeStyleSettings mySettings;
|
||||
private final LanguageLevel myLanguageLevel;
|
||||
|
||||
@@ -48,11 +52,74 @@ public class JDParser {
|
||||
myLanguageLevel = languageLevel;
|
||||
}
|
||||
|
||||
private static final char lineSeparator = '\n';
|
||||
public void formatCommentText(@NotNull PsiElement element, @NotNull CommentFormatter formatter) {
|
||||
CommentInfo info = getElementsCommentInfo(element);
|
||||
JDComment comment = info != null ? parse(info, formatter) : null;
|
||||
if (comment != null) {
|
||||
String indent = formatter.getIndent(info.getCommentOwner());
|
||||
String commentText = comment.generate(indent);
|
||||
formatter.replaceCommentText(commentText, (PsiDocComment)info.psiComment);
|
||||
}
|
||||
}
|
||||
|
||||
private CommentInfo getElementsCommentInfo(@Nullable PsiElement psiElement) {
|
||||
CommentInfo info = null;
|
||||
if (psiElement instanceof PsiDocComment) {
|
||||
final PsiDocComment docComment = (PsiDocComment)psiElement;
|
||||
if (docComment.getOwner() == null && docComment.getParent() instanceof PsiJavaFile) {
|
||||
info = CommentFormatter.getCommentInfo(docComment);
|
||||
if (info != null) {
|
||||
info.setCommentOwner(docComment);
|
||||
info.setComment(docComment);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return getElementsCommentInfo(psiElement.getParent());
|
||||
}
|
||||
}
|
||||
else if (psiElement instanceof PsiDocCommentOwner) {
|
||||
PsiDocCommentOwner owner = (PsiDocCommentOwner)psiElement;
|
||||
info = CommentFormatter.getOrigCommentInfo(owner);
|
||||
if (info != null) {
|
||||
info.setCommentOwner(owner);
|
||||
info.setComment(owner.getDocComment());
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
private JDComment parse(@NotNull CommentInfo info, @NotNull CommentFormatter formatter) {
|
||||
PsiElement owner = info.getCommentOwner();
|
||||
JDComment comment = createComment(owner, formatter);
|
||||
if (comment == null) return null;
|
||||
|
||||
parse(info.comment, comment);
|
||||
if (info.commentHeader != null) {
|
||||
comment.setFirstCommentLine(info.commentHeader);
|
||||
}
|
||||
if (info.commentFooter != null) {
|
||||
comment.setLastCommentLine(info.commentFooter);
|
||||
}
|
||||
|
||||
return comment;
|
||||
}
|
||||
|
||||
private JDComment createComment(@NotNull PsiElement psiElement, @NotNull CommentFormatter formatter) {
|
||||
if (psiElement instanceof PsiClass) {
|
||||
return new JDClassComment(formatter);
|
||||
}
|
||||
else if (psiElement instanceof PsiMethod) {
|
||||
return new JDMethodComment(formatter);
|
||||
}
|
||||
else if (psiElement instanceof PsiField || psiElement instanceof PsiDocComment) {
|
||||
return new JDComment(formatter);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JDComment parse(@Nullable String text, @NotNull JDComment comment) {
|
||||
if (text == null) return comment;
|
||||
private void parse(@Nullable String text, @NotNull JDComment comment) {
|
||||
if (text == null) return;
|
||||
|
||||
List<Boolean> markers = new ArrayList<Boolean>();
|
||||
List<String> l = toArray(text, "\n", markers);
|
||||
@@ -66,9 +133,9 @@ public class JDParser {
|
||||
comment.setMultiLine(true);
|
||||
}
|
||||
|
||||
if (l == null) return comment;
|
||||
if (l == null) return;
|
||||
int size = l.size();
|
||||
if (size == 0) return comment;
|
||||
if (size == 0) return;
|
||||
|
||||
// preprocess strings - removes first '*'
|
||||
for (int i = 0; i < size; i++) {
|
||||
@@ -140,8 +207,6 @@ public class JDParser {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return comment;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -544,4 +609,35 @@ public class JDParser {
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
public static class CommentInfo {
|
||||
public final String commentHeader;
|
||||
public final String comment;
|
||||
public final String commentFooter;
|
||||
|
||||
private PsiComment psiComment;
|
||||
private PsiElement myCommentOwner;
|
||||
|
||||
public CommentInfo(String commentHeader, String comment, String commentFooter) {
|
||||
this.commentHeader = commentHeader;
|
||||
this.comment = comment;
|
||||
this.commentFooter = commentFooter;
|
||||
}
|
||||
|
||||
public void setCommentOwner(PsiElement commentOwner) {
|
||||
myCommentOwner = commentOwner;
|
||||
}
|
||||
|
||||
public PsiElement getCommentOwner() {
|
||||
return myCommentOwner;
|
||||
}
|
||||
|
||||
public void setComment(PsiDocComment comment) {
|
||||
psiComment = comment;
|
||||
}
|
||||
|
||||
public PsiComment getComment() {
|
||||
return psiComment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public abstract class PsiTypeMapper extends PsiTypeVisitorEx<PsiType> {
|
||||
PsiType mappedComponent = mapType(componentType);
|
||||
if (mappedComponent == null) return null;
|
||||
if (mappedComponent == componentType) return type;
|
||||
return new PsiArrayType(mappedComponent);
|
||||
return new PsiArrayType(mappedComponent, type.getAnnotations());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,7 +51,7 @@ public abstract class PsiTypeMapper extends PsiTypeVisitorEx<PsiType> {
|
||||
PsiType mappedComponent = mapType(componentType);
|
||||
if (mappedComponent == null) return null;
|
||||
if (mappedComponent == componentType) return type;
|
||||
return new PsiEllipsisType(mappedComponent);
|
||||
return new PsiEllipsisType(mappedComponent, type.getAnnotations());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package p;
|
||||
|
||||
import java.io.FileReader;
|
||||
|
||||
class MyReader extends FileReader {}
|
||||
@@ -0,0 +1,11 @@
|
||||
package p;
|
||||
|
||||
class Foo {
|
||||
|
||||
{
|
||||
try (MyReader c1 = new MyReader() {}) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import foo.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
class TestCompilerWarnings {
|
||||
public void m(@NotNull Object x) {
|
||||
assert x != null;
|
||||
}
|
||||
|
||||
public void test1Array(@Nullable String @NotNull [] x) {
|
||||
if (<warning descr="Condition 'x == null' is always 'false'">x == null</warning>) {
|
||||
System.out.println("x is null");
|
||||
}
|
||||
m(x);
|
||||
m(<warning descr="Argument 'x[0]' might be null">x[0]</warning>);
|
||||
}
|
||||
|
||||
public void test2Array(@NotNull String @Nullable [] x) {
|
||||
if (x == null) {
|
||||
System.out.println("x is null");
|
||||
} else {
|
||||
m(x[0]);
|
||||
}
|
||||
m(<warning descr="Argument 'x' might be null">x</warning>);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
class Example {
|
||||
void foo() {
|
||||
Runnable runnable = () -> bar();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
String bar() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.intellij.codeInsight;
|
||||
|
||||
import com.intellij.idea.Bombed;
|
||||
import com.intellij.openapi.application.ex.PathManagerEx;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.roots.ModifiableRootModel;
|
||||
@@ -29,6 +30,8 @@ import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
|
||||
import com.intellij.testFramework.fixtures.*;
|
||||
import com.intellij.util.Consumer;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
public class MultipleJdksHighlightingTest extends UsefulTestCase {
|
||||
|
||||
private CodeInsightTestFixture myFixture;
|
||||
@@ -69,8 +72,7 @@ public class MultipleJdksHighlightingTest extends UsefulTestCase {
|
||||
ModuleRootModificationUtil.updateModel(myJava3Module, new Consumer<ModifiableRootModel>() {
|
||||
@Override
|
||||
public void consume(ModifiableRootModel model) {
|
||||
model.addModuleOrderEntry(myJava7Module);
|
||||
model.setSdk(IdeaTestUtil.getMockJdk17());
|
||||
model.setSdk(IdeaTestUtil.getMockJdk14());
|
||||
String contentUrl = VfsUtilCore.pathToUrl(myFixture.getTempDirPath()) + "/java3";
|
||||
model.addContentEntry(contentUrl).addSourceFolder(contentUrl, false);
|
||||
}
|
||||
@@ -79,7 +81,6 @@ public class MultipleJdksHighlightingTest extends UsefulTestCase {
|
||||
ModuleRootModificationUtil.updateModel(myJava7Module, new Consumer<ModifiableRootModel>() {
|
||||
@Override
|
||||
public void consume(ModifiableRootModel model) {
|
||||
model.addModuleOrderEntry(myJava8Module);
|
||||
model.setSdk(IdeaTestUtil.getMockJdk17());
|
||||
String contentUrl = VfsUtilCore.pathToUrl(myFixture.getTempDirPath()) + "/java7";
|
||||
model.addContentEntry(contentUrl).addSourceFolder(contentUrl, false);
|
||||
@@ -96,11 +97,18 @@ public class MultipleJdksHighlightingTest extends UsefulTestCase {
|
||||
});
|
||||
}
|
||||
|
||||
private void addDependencies_37_78() {
|
||||
ModuleRootModificationUtil.addDependency(myJava7Module, myJava8Module);
|
||||
ModuleRootModificationUtil.addDependency(myJava3Module, myJava7Module);
|
||||
}
|
||||
|
||||
public void testGetClass() throws Exception {
|
||||
addDependencies_37_78();
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testWrongSuperInLibrary() throws Exception {
|
||||
addDependencies_37_78();
|
||||
final String name = getTestName(false);
|
||||
for (Module module : new Module[] {myJava7Module, myJava8Module}) {
|
||||
ModuleRootModificationUtil.updateModel(module, new Consumer<ModifiableRootModel>() {
|
||||
@@ -116,42 +124,61 @@ public class MultipleJdksHighlightingTest extends UsefulTestCase {
|
||||
}
|
||||
|
||||
public void testWrongComparator() throws Exception {
|
||||
addDependencies_37_78();
|
||||
doTestWithoutLibrary();
|
||||
}
|
||||
|
||||
public void testGenericComparator() throws Exception {
|
||||
addDependencies_37_78();
|
||||
doTestWithoutLibrary();
|
||||
}
|
||||
|
||||
public void testGenericCallableWithDifferentTypeArgs() throws Exception {
|
||||
addDependencies_37_78();
|
||||
doTestWithoutLibrary();
|
||||
}
|
||||
|
||||
public void testSuperclassImplementsUnknownType() throws Exception {
|
||||
addDependencies_37_78();
|
||||
doTestWithoutLibrary();
|
||||
}
|
||||
|
||||
public void testDeclaredTypeOfVariableImplementsUnknownType() throws Exception {
|
||||
addDependencies_37_78();
|
||||
doTestWithoutLibrary();
|
||||
}
|
||||
|
||||
public void testSuperclassImplementsGenericsOfUnknownType() throws Exception {
|
||||
addDependencies_37_78();
|
||||
doTestWithoutLibrary();
|
||||
}
|
||||
|
||||
public void testSuperMethodNotExist() throws Exception {
|
||||
addDependencies_37_78();
|
||||
doTestWithoutLibrary();
|
||||
}
|
||||
|
||||
public void testNoOverriding() throws Exception {
|
||||
addDependencies_37_78();
|
||||
doTestWithoutLibrary();
|
||||
}
|
||||
|
||||
public void testStaticCallOnChildWithNotAccessibleParent() throws Exception {
|
||||
addDependencies_37_78();
|
||||
doTest3Modules();
|
||||
}
|
||||
|
||||
@Bombed(user = "peter,anna", year = 2015, month = Calendar.MAY, day = 1)
|
||||
public void testCloseableAutoCloseable() {
|
||||
ModuleRootModificationUtil.addDependency(myJava7Module, myJava3Module);
|
||||
final String name = getTestName(false);
|
||||
myFixture.copyFileToProject("java3/p/" + name + ".java");
|
||||
myFixture.configureByFiles("java7/p/" + name + ".java");
|
||||
myFixture.checkHighlighting();
|
||||
}
|
||||
|
||||
public void testLanguageLevelInReturnTypeCheck() throws Exception {
|
||||
addDependencies_37_78();
|
||||
final String name = getTestName(false);
|
||||
myFixture.configureByFiles("java3/p/" + name + ".java", "java7/p/" + name + ".java");
|
||||
myFixture.checkHighlighting();
|
||||
|
||||
@@ -77,9 +77,18 @@ public class DataFlowInspection8Test extends LightCodeInsightFixtureTestCase {
|
||||
}
|
||||
|
||||
public void testMethodReferenceOnNullable() { doTest(); }
|
||||
public void testNullableVoidLambda() { doTest(); }
|
||||
|
||||
public void testNullableForeachVariable() {
|
||||
setupCustomAnnotations();
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testNullableArrayComponent() {
|
||||
setupCustomAnnotations();
|
||||
final DataFlowInspection inspection = new DataFlowInspection();
|
||||
inspection.IGNORE_ASSERT_STATEMENTS = true;
|
||||
myFixture.enableInspections(inspection);
|
||||
myFixture.testHighlighting(true, false, true, getTestName(false) + ".java");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,61 @@ public class JavadocFormatterTest extends AbstractJavaFormatterTest {
|
||||
);
|
||||
}
|
||||
|
||||
public void test_do_wrap_on_asterisks() {
|
||||
doTextTest(
|
||||
"/***********\n" +
|
||||
" *\n" +
|
||||
" *********************/\n" +
|
||||
"\n" +
|
||||
"\n" +
|
||||
" public class Test {\n" +
|
||||
"}\n",
|
||||
"/***********\n" +
|
||||
" *\n" +
|
||||
" *********************/\n" +
|
||||
"\n" +
|
||||
"\n" +
|
||||
"public class Test {\n" +
|
||||
"}\n"
|
||||
);
|
||||
}
|
||||
|
||||
public void test_wrap_after_asterisks() {
|
||||
doTextTest(
|
||||
"/******* hollla la\n" +
|
||||
" * I am javadoc comment\n" +
|
||||
" * heey ***********/\n" +
|
||||
" class T { }\n",
|
||||
"/*******\n" +
|
||||
" * hollla la\n" +
|
||||
" * I am javadoc comment\n" +
|
||||
" * heey\n" +
|
||||
" ***********/\n" +
|
||||
"class T {\n" +
|
||||
"}\n"
|
||||
);
|
||||
}
|
||||
|
||||
public void test_strange_comment() {
|
||||
doTextTest(
|
||||
"/******F*****/\n" +
|
||||
"public class T {\n" +
|
||||
"}",
|
||||
"/******\n" +
|
||||
" * F\n" +
|
||||
" *****/\n" +
|
||||
"public class T {\n" +
|
||||
"}"
|
||||
);
|
||||
}
|
||||
|
||||
public void test_incomplete_javadoc() {
|
||||
doTextTest(
|
||||
"/**\n",
|
||||
"/**\n"
|
||||
);
|
||||
}
|
||||
|
||||
public void testEA49739() throws Exception {
|
||||
getSettings().WRAP_LONG_LINES = true;
|
||||
getSettings().RIGHT_MARGIN = 35;
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package com.intellij.util.indexing;
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import com.intellij.psi.stubs.StubUpdatingIndex;
|
||||
import com.intellij.testFramework.LightVirtualFile;
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
|
||||
import com.intellij.util.text.CharArrayCharSequence;
|
||||
|
||||
/**
|
||||
* @author Dmitry Avdeev
|
||||
@@ -15,4 +19,14 @@ public class FileBasedIndexTest extends LightCodeInsightFixtureTestCase {
|
||||
myFixture.configureByText("Bar.java", "class Bar { String bar; }");
|
||||
myFixture.testHighlighting();
|
||||
}
|
||||
|
||||
public void testLargeFile() throws Exception {
|
||||
char[] text = new char[FileUtilRt.LARGE_FOR_CONTENT_LOADING + 42];
|
||||
final String clazz = "class Foo { String bar; }";
|
||||
for (int i = 0; i < text.length; i++) {
|
||||
text[i] = i < clazz.length() ? clazz.charAt(i) : ' ';
|
||||
}
|
||||
final LightVirtualFile file = new LightVirtualFile("Foo.java", new CharArrayCharSequence(text));
|
||||
assertFalse(((FileBasedIndexImpl)FileBasedIndex.getInstance()).isIndexingCandidate(file, StubUpdatingIndex.INDEX_ID));
|
||||
}
|
||||
}
|
||||
|
||||
+9
-9
@@ -1478,20 +1478,20 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
|
||||
new1.getArrayDimensions().length == 0 &&
|
||||
new1.getArrayInitializer() != null
|
||||
) {
|
||||
final MatchContext matchContext = myMatchingVisitor.getMatchContext();
|
||||
final MatchingHandler handler = matchContext.getPattern().getHandler(classReference);
|
||||
final boolean looseMatching = myMatchingVisitor.getMatchContext().getOptions().isLooseMatching();
|
||||
final boolean typedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(classReference);
|
||||
if ((typedVar || !looseMatching) && !allowsAbsenceOfMatch(classReference)) {
|
||||
if ((handler instanceof SubstitutionHandler && ((SubstitutionHandler)handler).getMinOccurs() != 0) || !looseMatching) {
|
||||
myMatchingVisitor.setResult(false);
|
||||
return;
|
||||
}
|
||||
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(other.getProject());
|
||||
final PsiType otherType = ((PsiVariable)other.getParent()).getType();
|
||||
final PsiTypeElement otherTypeElement = factory.createTypeElement(otherType.getDeepComponentType());
|
||||
final MatchContext matchContext = myMatchingVisitor.getMatchContext();
|
||||
final MatchingHandler handler = matchContext.getPattern().getHandler(classReference);
|
||||
if (handler instanceof SubstitutionHandler) {
|
||||
final PsiType otherType = ((PsiArrayInitializerExpression)other).getType();
|
||||
if (handler instanceof SubstitutionHandler && otherType != null) {
|
||||
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(other.getProject());
|
||||
final PsiTypeElement otherTypeElement = factory.createTypeElement(otherType.getDeepComponentType());
|
||||
final SubstitutionHandler substitutionHandler = (SubstitutionHandler)handler;
|
||||
myMatchingVisitor.setResult(substitutionHandler.handle(otherTypeElement, matchContext));
|
||||
final MatchPredicate predicate = substitutionHandler.getPredicate();
|
||||
myMatchingVisitor.setResult(predicate == null || predicate.match(null, otherTypeElement, matchContext));
|
||||
}
|
||||
else {
|
||||
final PsiType type = new1.getType();
|
||||
|
||||
@@ -133,7 +133,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
|
||||
@Nullable ASTNode originalTree,
|
||||
@Nullable MyTreeStructure parentLightTree) {
|
||||
this(project, containingFile, parserDefinition.getWhitespaceTokens(), parserDefinition.getCommentTokens(), lexer, charTable, text,
|
||||
originalTree, parentLightTree, 0);
|
||||
originalTree, parentLightTree, null);
|
||||
}
|
||||
|
||||
public PsiBuilderImpl(Project project,
|
||||
@@ -145,7 +145,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
|
||||
@NotNull final CharSequence text,
|
||||
@Nullable ASTNode originalTree,
|
||||
@Nullable MyTreeStructure parentLightTree) {
|
||||
this(project, containingFile, whiteSpaces, comments, lexer, charTable, text, originalTree, parentLightTree, 0);
|
||||
this(project, containingFile, whiteSpaces, comments, lexer, charTable, text, originalTree, parentLightTree, null);
|
||||
}
|
||||
|
||||
private PsiBuilderImpl(Project project,
|
||||
@@ -157,7 +157,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
|
||||
@NotNull final CharSequence text,
|
||||
@Nullable ASTNode originalTree,
|
||||
@Nullable MyTreeStructure parentLightTree,
|
||||
int offset) {
|
||||
LazyParseableToken parentToken) {
|
||||
myProject = project;
|
||||
myFile = containingFile;
|
||||
|
||||
@@ -170,9 +170,9 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
|
||||
myCharTable = charTable;
|
||||
myOriginalTree = originalTree;
|
||||
myParentLightTree = parentLightTree;
|
||||
myOffset = offset;
|
||||
myOffset = parentToken != null ? parentToken.getStartOffset() : 0;
|
||||
|
||||
cacheLexemes();
|
||||
cacheLexemes(parentToken);
|
||||
}
|
||||
|
||||
public PsiBuilderImpl(@NotNull final Project project,
|
||||
@@ -190,10 +190,41 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
|
||||
@NotNull final LighterLazyParseableNode chameleon,
|
||||
@NotNull final CharSequence text) {
|
||||
this(project, chameleon.getContainingFile(), parserDefinition.getWhitespaceTokens(), parserDefinition.getCommentTokens(), lexer,
|
||||
chameleon.getCharTable(), text, null, ((LazyParseableToken)chameleon).myParent, chameleon.getStartOffset());
|
||||
chameleon.getCharTable(), text, null, ((LazyParseableToken)chameleon).myParent, ((LazyParseableToken)chameleon)
|
||||
);
|
||||
}
|
||||
|
||||
private void cacheLexemes() {
|
||||
private void cacheLexemes(LazyParseableToken parentToken) {
|
||||
int[] lexStarts = null;
|
||||
IElementType[] lexTypes = null;
|
||||
int lexemeCount = -1;
|
||||
boolean doLexingOptimizationCorrectionCheck = false;
|
||||
|
||||
if (parentToken != null) {
|
||||
// there are two types of lazy parseable tokens out there: collapsed out of individual tokens or single token that needs to be expanded
|
||||
// in first case parent PsiBuilder has all our text lexed so no need to do it again
|
||||
int tokenCount = parentToken.myEndIndex - parentToken.myStartIndex;
|
||||
if (tokenCount != 1) { // not expand single lazy parseable token case
|
||||
lexStarts = new int[tokenCount + 1];
|
||||
System.arraycopy(parentToken.myBuilder.myLexStarts, parentToken.myStartIndex, lexStarts, 0, tokenCount);
|
||||
int diff = parentToken.myBuilder.myLexStarts[parentToken.myStartIndex];
|
||||
for(int i = 0; i < tokenCount; ++i) lexStarts[i] -= diff;
|
||||
lexStarts[tokenCount] = myText.length();
|
||||
|
||||
lexTypes = new IElementType[tokenCount];
|
||||
System.arraycopy(parentToken.myBuilder.myLexTypes, parentToken.myStartIndex, lexTypes, 0, tokenCount);
|
||||
lexemeCount = tokenCount;
|
||||
}
|
||||
ProgressIndicatorProvider.checkCanceled();
|
||||
|
||||
if (!doLexingOptimizationCorrectionCheck) {
|
||||
myLexStarts = lexStarts;
|
||||
myLexTypes = lexTypes;
|
||||
myLexemeCount = lexemeCount;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int approxLexCount = Math.max(10, myText.length() / 5);
|
||||
|
||||
myLexStarts = new int[approxLexCount];
|
||||
@@ -216,7 +247,8 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
|
||||
final IElementType tokenType = myLexer.getTokenType();
|
||||
sb.append("Token sequence broken")
|
||||
.append("\n this: '").append(myLexer.getTokenText()).append("' (").append(tokenType).append(':')
|
||||
.append(tokenType != null ? tokenType.getLanguage() : null).append(") ").append(tokenStart).append(":").append(myLexer.getTokenEnd());
|
||||
.append(tokenType != null ? tokenType.getLanguage() : null).append(") ").append(tokenStart).append(":")
|
||||
.append(myLexer.getTokenEnd());
|
||||
if (i > 0) {
|
||||
final int prevStart = myLexStarts[i - 1];
|
||||
sb.append("\n prev: '").append(myText.subSequence(prevStart, offset)).append("' (").append(myLexTypes[i - 1]).append(':')
|
||||
@@ -238,6 +270,19 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
|
||||
|
||||
myLexemeCount = i;
|
||||
clearCachedTokenType();
|
||||
|
||||
//noinspection ConstantConditions
|
||||
if (doLexingOptimizationCorrectionCheck) {
|
||||
if (lexemeCount != -1) {
|
||||
assert lexemeCount == myLexemeCount;
|
||||
for(int j = 0; j < lexemeCount; ++j) {
|
||||
if (myLexStarts[j] != lexStarts[j] || myLexTypes[j] != lexTypes[j]) {
|
||||
assert false;
|
||||
}
|
||||
}
|
||||
assert myLexStarts[lexemeCount] == lexStarts[lexemeCount];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1215,8 +1260,8 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
|
||||
CharSequence context =
|
||||
index < myLexStarts.length ? myText.subSequence(Math.max(0, myLexStarts[index] - 1000), myLexStarts[index]) : "<none>";
|
||||
String language = myFile != null ? myFile.getLanguage() + ", " : "";
|
||||
LOG.error(UNBALANCED_MESSAGE + "\n" +
|
||||
"language: " + language + "\n" +
|
||||
LOG.error(UNBALANCED_MESSAGE + "\n" +
|
||||
"language: " + language + "\n" +
|
||||
"context: '" + context + "'");
|
||||
}
|
||||
|
||||
|
||||
@@ -161,15 +161,18 @@ public class FoldingModelSupport {
|
||||
|
||||
private void addRange(int[] starts, int[] ends) {
|
||||
List<FoldedBlock> result = new ArrayList<FoldedBlock>(3);
|
||||
int[] rangeStarts = new int[myCount];
|
||||
int[] rangeEnds = new int[myCount];
|
||||
|
||||
for (int number = 0; ; number++) {
|
||||
int shift = getRangeShift(mySettings.range, number);
|
||||
if (shift == -1) break;
|
||||
|
||||
for (int i = 0; i < myCount; i++) {
|
||||
starts[i] = bound(starts[i] + shift, i);
|
||||
ends[i] = bound(ends[i] - shift, i);
|
||||
rangeStarts[i] = bound(starts[i] + shift, i);
|
||||
rangeEnds[i] = bound(ends[i] - shift, i);
|
||||
}
|
||||
ContainerUtil.addAllNotNull(result, createRange(starts, ends, myExpandSuggester.isExpanded(starts, ends)));
|
||||
ContainerUtil.addAllNotNull(result, createRange(rangeStarts, rangeEnds, myExpandSuggester.isExpanded(rangeStarts, rangeEnds)));
|
||||
}
|
||||
|
||||
if (result.size() > 0) {
|
||||
@@ -700,20 +703,17 @@ public class FoldingModelSupport {
|
||||
//
|
||||
|
||||
/*
|
||||
* number:
|
||||
* 0: unchanged -> first folding
|
||||
* 1: first folding-> second folding
|
||||
* ...
|
||||
* -1 - end
|
||||
* number - depth of folding insertion (from zero)
|
||||
* return: number of context lines. ('-1' - end)
|
||||
*/
|
||||
private static int getRangeShift(int range, int number) {
|
||||
switch (number) {
|
||||
case 0:
|
||||
return range;
|
||||
case 1:
|
||||
return range;
|
||||
case 2:
|
||||
return range * 2;
|
||||
case 2:
|
||||
return range * 4;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.DataProvider;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.impl.LaterInvocator;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.components.StoragePathMacros;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -822,7 +823,7 @@ public class DiffUtil {
|
||||
public static WindowWrapper.Mode getWindowMode(@NotNull DiffDialogHints hints) {
|
||||
WindowWrapper.Mode mode = hints.getMode();
|
||||
if (mode == null) {
|
||||
boolean isUnderDialog = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow() instanceof JDialog;
|
||||
boolean isUnderDialog = LaterInvocator.isInModalContext();
|
||||
mode = isUnderDialog ? WindowWrapper.Mode.MODAL : WindowWrapper.Mode.FRAME;
|
||||
}
|
||||
return mode;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -336,10 +336,11 @@ public class TargetElementUtilBase {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<PsiElement> getTargetCandidates(PsiReference reference) {
|
||||
if (reference instanceof PsiPolyVariantReference) {
|
||||
final ResolveResult[] results = ((PsiPolyVariantReference)reference).multiResolve(false);
|
||||
final ArrayList<PsiElement> navigatableResults = new ArrayList<PsiElement>(results.length);
|
||||
List<PsiElement> navigatableResults = new ArrayList<PsiElement>(results.length);
|
||||
|
||||
for(ResolveResult r:results) {
|
||||
PsiElement element = r.getElement();
|
||||
|
||||
+3
@@ -60,6 +60,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
@@ -345,6 +346,8 @@ public abstract class AbstractLayoutCodeProcessor {
|
||||
try {
|
||||
task.get();
|
||||
}
|
||||
catch (CancellationException ignored) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -558,7 +558,7 @@ public class CtrlMouseHandler extends AbstractProjectComponent {
|
||||
}
|
||||
}
|
||||
|
||||
final PsiNameIdentifierOwner element = GotoDeclarationAction.findElementToShowUsagesOf(editor, file, offset);
|
||||
final PsiNameIdentifierOwner element = GotoDeclarationAction.findElementToShowUsagesOf(editor, offset);
|
||||
if (element != null) {
|
||||
PsiElement identifier = element.getNameIdentifier();
|
||||
return new Info(identifier){
|
||||
|
||||
+6
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -83,8 +83,8 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code
|
||||
FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.goto.declaration");
|
||||
|
||||
if (elements.length != 1) {
|
||||
if (elements.length == 0) {
|
||||
PsiElement element = findElementToShowUsagesOf(editor, file, editor.getCaretModel().getOffset());
|
||||
if (elements.length == 0 && suggestCandidates(TargetElementUtilBase.findReference(editor, offset)).isEmpty()) {
|
||||
PsiElement element = findElementToShowUsagesOf(editor, editor.getCaretModel().getOffset());
|
||||
if (element != null) {
|
||||
ShowUsagesAction showUsages = (ShowUsagesAction)ActionManager.getInstance().getAction(ShowUsagesAction.ID);
|
||||
RelativePoint popupPosition = JBPopupFactory.getInstance().guessBestPopupLocation(editor);
|
||||
@@ -111,7 +111,7 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code
|
||||
}
|
||||
}
|
||||
|
||||
public static PsiNameIdentifierOwner findElementToShowUsagesOf(@NotNull Editor editor, @NotNull PsiFile file, int offset) {
|
||||
public static PsiNameIdentifierOwner findElementToShowUsagesOf(@NotNull Editor editor, int offset) {
|
||||
PsiElement elementAt = TargetElementUtilBase.getInstance().findTargetElement(editor, TargetElementUtilBase.ELEMENT_NAME_ACCEPTED, offset);
|
||||
if (elementAt instanceof PsiNameIdentifierOwner) {
|
||||
return (PsiNameIdentifierOwner)elementAt;
|
||||
@@ -184,7 +184,8 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Collection<PsiElement> suggestCandidates(final PsiReference reference) {
|
||||
@NotNull
|
||||
private static Collection<PsiElement> suggestCandidates(@Nullable PsiReference reference) {
|
||||
if (reference == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
+18
-16
@@ -325,12 +325,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
appendPairedInspectionsForUnfairTools(globalTools, globalSimpleTools, localTools);
|
||||
|
||||
((RefManagerImpl)getRefManager()).initializeAnnotators();
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
runGlobalTools(scope, inspectionManager, globalTools);
|
||||
}
|
||||
});
|
||||
runGlobalTools(scope, inspectionManager, globalTools);
|
||||
|
||||
if (runGlobalToolsOnly) return;
|
||||
|
||||
@@ -497,15 +492,16 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
return PsiDocumentManager.getInstance(getProject()).getDocument(file);
|
||||
}
|
||||
|
||||
private void runGlobalTools(@NotNull AnalysisScope scope, @NotNull InspectionManager inspectionManager, @NotNull List<Tools> globalTools) {
|
||||
private void runGlobalTools(@NotNull final AnalysisScope scope, @NotNull final InspectionManager inspectionManager, @NotNull List<Tools> globalTools) {
|
||||
LOG.assertTrue(!ApplicationManager.getApplication().isReadAccessAllowed(), "Must not run under read action, too unresponsive");
|
||||
final List<InspectionToolWrapper> needRepeatSearchRequest = new ArrayList<InspectionToolWrapper>();
|
||||
|
||||
final boolean surelyNoExternalUsages = scope.getScopeType() == AnalysisScope.PROJECT;
|
||||
final boolean canBeExternalUsages = scope.getScopeType() != AnalysisScope.PROJECT;
|
||||
for (Tools tools : globalTools) {
|
||||
for (ScopeToolState state : tools.getTools()) {
|
||||
InspectionToolWrapper toolWrapper = state.getTool();
|
||||
GlobalInspectionTool tool = (GlobalInspectionTool)toolWrapper.getTool();
|
||||
InspectionToolPresentation toolPresentation = getPresentation(toolWrapper);
|
||||
final InspectionToolWrapper toolWrapper = state.getTool();
|
||||
final GlobalInspectionTool tool = (GlobalInspectionTool)toolWrapper.getTool();
|
||||
final InspectionToolPresentation toolPresentation = getPresentation(toolWrapper);
|
||||
try {
|
||||
if (tool.isGraphNeeded()) {
|
||||
try {
|
||||
@@ -516,11 +512,17 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
tool.runInspection(scope, inspectionManager, this, toolPresentation);
|
||||
//skip phase when we are sure that scope already contains everything
|
||||
if (!surelyNoExternalUsages && tool.queryExternalUsagesRequests(inspectionManager, this, toolPresentation)) {
|
||||
needRepeatSearchRequest.add(toolWrapper);
|
||||
}
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
tool.runInspection(scope, inspectionManager, GlobalInspectionContextImpl.this, toolPresentation);
|
||||
//skip phase when we are sure that scope already contains everything
|
||||
if (canBeExternalUsages &&
|
||||
tool.queryExternalUsagesRequests(inspectionManager, GlobalInspectionContextImpl.this, toolPresentation)) {
|
||||
needRepeatSearchRequest.add(toolWrapper);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
throw e;
|
||||
|
||||
@@ -2456,14 +2456,14 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
|
||||
private boolean isTooLarge(@NotNull VirtualFile file) {
|
||||
if (SingleRootFileViewProvider.isTooLargeForIntelligence(file)) {
|
||||
return !myNoLimitCheckTypes.contains(file.getFileType()) && !SingleRootFileViewProvider.isTooLargeForContentLoading(file);
|
||||
return !myNoLimitCheckTypes.contains(file.getFileType()) || SingleRootFileViewProvider.isTooLargeForContentLoading(file);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isTooLarge(@NotNull VirtualFile file, long contentSize) {
|
||||
if (SingleRootFileViewProvider.isTooLargeForIntelligence(file, contentSize)) {
|
||||
return !myNoLimitCheckTypes.contains(file.getFileType()) && !SingleRootFileViewProvider.isTooLargeForContentLoading(file, contentSize);
|
||||
return !myNoLimitCheckTypes.contains(file.getFileType()) || SingleRootFileViewProvider.isTooLargeForContentLoading(file, contentSize);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -269,7 +269,7 @@ public class DumbServiceImpl extends DumbService implements Disposable, Modifica
|
||||
runnable.run();
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.error(e);
|
||||
LOG.error("Error executing task " + runnable, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+41
-6
@@ -15,28 +15,63 @@
|
||||
*/
|
||||
package com.intellij.openapi.wm.impl.welcomeScreen;
|
||||
|
||||
import com.intellij.ide.ProjectGroupActionGroup;
|
||||
import com.intellij.ide.ReopenProjectAction;
|
||||
import com.intellij.openapi.actionSystem.ActionPlaces;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.Presentation;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
|
||||
import java.awt.event.InputEvent;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Konstantin Bulenkov
|
||||
*/
|
||||
public class OpenSelectedProjectsAction extends DumbAwareAction {
|
||||
public class OpenSelectedProjectsAction extends RecentProjectsWelcomeScreenActionBase {
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
|
||||
List<AnAction> elements = getSelectedElements(e);
|
||||
e = new AnActionEvent(e.getInputEvent(), e.getDataContext(), e.getPlace(), e.getPresentation(), e.getActionManager(), InputEvent.SHIFT_MASK);
|
||||
for (AnAction element : elements) {
|
||||
if (element instanceof ProjectGroupActionGroup) {
|
||||
for (AnAction action : ((ProjectGroupActionGroup)element).getChildren(e)) {
|
||||
action.actionPerformed(e);
|
||||
}
|
||||
} else {
|
||||
element.actionPerformed(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
final Presentation presentation = e.getPresentation();
|
||||
List<AnAction> selectedElements = getSelectedElements(e);
|
||||
boolean hasProject = false;
|
||||
boolean hasGroup = false;
|
||||
for (AnAction element : selectedElements) {
|
||||
if (element instanceof ReopenProjectAction) {
|
||||
hasProject = true;
|
||||
}
|
||||
if (element instanceof ProjectGroupActionGroup) {
|
||||
hasGroup = true;
|
||||
}
|
||||
|
||||
if (hasGroup && hasProject) {
|
||||
e.getPresentation().setEnabled(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (ActionPlaces.WELCOME_SCREEN.equals(e.getPlace())) {
|
||||
presentation.setEnabledAndVisible(true);
|
||||
presentation.setText("Open Selected");
|
||||
return;
|
||||
if (selectedElements.size() == 1 && selectedElements.get(0) instanceof ProjectGroupActionGroup) {
|
||||
presentation.setText("Open All Projects in Group");
|
||||
} else {
|
||||
presentation.setText("Open Selected");
|
||||
}
|
||||
} else {
|
||||
presentation.setEnabledAndVisible(false);
|
||||
}
|
||||
presentation.setEnabledAndVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ public class EditorComboBox extends JComboBox implements DocumentListener {
|
||||
@Override
|
||||
public void setItem(Object anObject) {
|
||||
if (anObject != null) {
|
||||
EditorComboBox.this.setText((String)anObject);
|
||||
EditorComboBox.this.setText(anObject.toString());
|
||||
} else {
|
||||
EditorComboBox.this.setText("");
|
||||
}
|
||||
|
||||
+29
-6
@@ -551,13 +551,36 @@ public class StructuralSearchTest extends StructuralSearchTestCase {
|
||||
|
||||
String s9 = "int a[] = new int[] { 1,2,3,4};\n" +
|
||||
"int b[] = { 2,3,4,5 };\n" +
|
||||
"Object[] c = new Object[] { \"\", null};";
|
||||
"Object[] c = new Object[] { \"\", null};\n" +
|
||||
"Object[] d = {null, null};\n" +
|
||||
"Object[] e = {};\n" +
|
||||
"Object[] f = new Object[]{}\n" +
|
||||
"String[] g = new String[]{}\n" +
|
||||
"String[] h = new String[]{new String()}";
|
||||
|
||||
assertEquals("Find array instantiation 1", 2, findMatchesCount(s9, "new '_ []{ '_* }"));
|
||||
assertEquals("Find array instantiation 2", 2, findMatchesCount(s9, "new int []{ '_* }"));
|
||||
assertEquals("Find array instantiation 3", 2, findMatchesCount(s9, "new 'a?:int [] { '_* }"));
|
||||
assertEquals("Find array instantiation 4", 3, findMatchesCount(s9, "new '_? []{ '_* }"));
|
||||
assertEquals("Find array instantiation 5", 1, findMatchesCount(s9, "new Object[] { '_* }"));
|
||||
assertEquals("Find new array expressions, but no array initializer expressions", 5,
|
||||
findMatchesCount(s9, "new '_ []{ '_* }"));
|
||||
|
||||
assertEquals("Find new int array expressions, including array initializer expressions", 2,
|
||||
findMatchesCount(s9, "new int []{ '_* }"));
|
||||
|
||||
assertEquals("Find new int array expressions, including array initializer expressions using variable ", 2,
|
||||
findMatchesCount(s9, "new 'a?:int [] { '_* }"));
|
||||
|
||||
assertEquals("Find all new array expressions, including array initializers", 8,
|
||||
findMatchesCount(s9, "new '_? []{ '_* }"));
|
||||
|
||||
assertEquals("Find new Object array expressions, including array initializer expressions", 4,
|
||||
findMatchesCount(s9, "new Object[] { '_* }"));
|
||||
|
||||
assertEquals("Find only array initializer expressions", 3,
|
||||
findMatchesCount(s9, "new '_{0,0}[] { '_* }"));
|
||||
|
||||
assertEquals("Find only int array initializer expressions", 1,
|
||||
findMatchesCount(s9, "new '_{0,0}:int [] { '_* }"));
|
||||
|
||||
assertEquals("Try to find String array initializer expressions", 0,
|
||||
findMatchesCount(s9, "new '_{0,0}:String [] { '_* }"));
|
||||
}
|
||||
|
||||
public void testLiteral() {
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.intellij.util.ConcurrencyUtil;
|
||||
import com.intellij.util.containers.WeakList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.Notification;
|
||||
import javax.management.NotificationEmitter;
|
||||
import javax.management.NotificationListener;
|
||||
@@ -66,6 +67,21 @@ public class LowMemoryWatcher {
|
||||
}
|
||||
}
|
||||
};
|
||||
private static final NotificationListener ourLowMemoryListener = new NotificationListener() {
|
||||
@Override
|
||||
public void handleNotification(Notification n, Object hb) {
|
||||
if (MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED.equals(n.getType()) ||
|
||||
MemoryNotificationInfo.MEMORY_COLLECTION_THRESHOLD_EXCEEDED.equals(n.getType())) {
|
||||
synchronized (ourJanitor) {
|
||||
if (!ourSubmitted) {
|
||||
//noinspection AssignmentToStaticFieldFromInstanceMethod
|
||||
ourSubmitted = true;
|
||||
ourExecutor.submit(ourJanitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final Runnable myRunnable;
|
||||
|
||||
@@ -79,20 +95,7 @@ public class LowMemoryWatcher {
|
||||
}
|
||||
}
|
||||
}
|
||||
((NotificationEmitter)ManagementFactory.getMemoryMXBean()).addNotificationListener(new NotificationListener() {
|
||||
@Override
|
||||
public void handleNotification(Notification n, Object hb) {
|
||||
if (MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED.equals(n.getType()) || MemoryNotificationInfo.MEMORY_COLLECTION_THRESHOLD_EXCEEDED.equals(n.getType())) {
|
||||
synchronized (ourJanitor) {
|
||||
if (!ourSubmitted) {
|
||||
//noinspection AssignmentToStaticFieldFromInstanceMethod
|
||||
ourSubmitted = true;
|
||||
ourExecutor.submit(ourJanitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, null, null);
|
||||
((NotificationEmitter)ManagementFactory.getMemoryMXBean()).addNotificationListener(ourLowMemoryListener, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,6 +138,12 @@ public class LowMemoryWatcher {
|
||||
public static void stopAll() {
|
||||
ourExecutor.shutdown();
|
||||
ourInstances.clear();
|
||||
try {
|
||||
((NotificationEmitter)ManagementFactory.getMemoryMXBean()).removeNotificationListener(ourLowMemoryListener);
|
||||
}
|
||||
catch (ListenerNotFoundException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ import com.intellij.ui.content.ContentManager;
|
||||
import com.intellij.ui.dualView.*;
|
||||
import com.intellij.ui.table.TableView;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.text.DateFormatUtil;
|
||||
import com.intellij.util.ui.*;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -764,12 +765,13 @@ public class FileHistoryPanelImpl extends PanelWithActionsAndCloseButton {
|
||||
final MyDiffAction diffAction = new MyDiffAction();
|
||||
result.add(diffAction);
|
||||
if (!popup) {
|
||||
diffAction.registerCustomShortcutSet(new CustomShortcutSet(
|
||||
CommonShortcuts.getDiff().getShortcuts() [0],
|
||||
CommonShortcuts.DOUBLE_CLICK_1.getShortcuts() [0]), myDualView.getFlatView());
|
||||
diffAction.registerCustomShortcutSet(new CustomShortcutSet(
|
||||
CommonShortcuts.getDiff().getShortcuts() [0],
|
||||
CommonShortcuts.DOUBLE_CLICK_1.getShortcuts() [0]), myDualView.getTreeView());
|
||||
List<Shortcut> shortcuts = new SmartList<Shortcut>();
|
||||
ContainerUtil.addAll(shortcuts, CommonShortcuts.getDiff().getShortcuts());
|
||||
ContainerUtil.addAll(shortcuts, CommonShortcuts.DOUBLE_CLICK_1.getShortcuts());
|
||||
CustomShortcutSet shortcutSet = new CustomShortcutSet(ContainerUtil.toArray(shortcuts, new Shortcut[shortcuts.size()]));
|
||||
|
||||
diffAction.registerCustomShortcutSet(shortcutSet, myDualView.getFlatView());
|
||||
diffAction.registerCustomShortcutSet(shortcutSet, myDualView.getTreeView());
|
||||
}
|
||||
else {
|
||||
diffAction.registerCustomShortcutSet(CommonShortcuts.getDiff(), this);
|
||||
|
||||
+16
-1
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.xdebugger.impl.settings;
|
||||
|
||||
import com.intellij.openapi.options.Configurable;
|
||||
@@ -121,7 +136,7 @@ class MergedCompositeConfigurable implements SearchableConfigurable {
|
||||
@NotNull
|
||||
static JPanel createPanel(boolean isUseTitledBorder) {
|
||||
int verticalGap = TitledSeparator.TOP_INSET;
|
||||
JPanel panel = new JPanel(new VerticalFlowLayout(0, isUseTitledBorder ? 0 : verticalGap));
|
||||
JPanel panel = new JPanel(new VerticalFlowLayout(VerticalFlowLayout.TOP, 0, isUseTitledBorder ? 0 : verticalGap, true, true));
|
||||
// VerticalFlowLayout incorrectly use vertical gap as top inset
|
||||
if (!isUseTitledBorder) {
|
||||
panel.setBorder(new EmptyBorder(-verticalGap, 0, 0, 0));
|
||||
|
||||
@@ -157,6 +157,7 @@
|
||||
<projectService
|
||||
serviceInterface="git4idea.config.GitVcsSettings"
|
||||
serviceImplementation="git4idea.config.GitVcsSettings"/>
|
||||
<projectService serviceImplementation="git4idea.config.GitRebaseSettings"/>
|
||||
<projectService serviceImplementation="git4idea.config.GitSharedSettings" />
|
||||
<projectService
|
||||
serviceInterface="git4idea.config.GitExecutableValidator"
|
||||
|
||||
@@ -17,16 +17,17 @@ package git4idea.actions;
|
||||
|
||||
import com.intellij.dvcs.DvcsUtil;
|
||||
import com.intellij.openapi.application.AccessToken;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.VcsNotifier;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import git4idea.GitUtil;
|
||||
import git4idea.commands.Git;
|
||||
import git4idea.commands.GitCommandResult;
|
||||
import git4idea.commands.GitLineHandler;
|
||||
import git4idea.commands.GitTask;
|
||||
import git4idea.commands.GitTaskResult;
|
||||
import git4idea.commands.GitTaskResultHandlerAdapter;
|
||||
import git4idea.i18n.GitBundle;
|
||||
import git4idea.rebase.GitInteractiveRebaseEditorHandler;
|
||||
import git4idea.rebase.GitRebaseEditorService;
|
||||
@@ -50,7 +51,7 @@ public abstract class GitRebaseActionBase extends GitRepositoryAction {
|
||||
@NotNull final VirtualFile defaultRoot,
|
||||
final Set<VirtualFile> affectedRoots,
|
||||
final List<VcsException> exceptions) throws VcsException {
|
||||
GitLineHandler h = createHandler(project, gitRoots, defaultRoot);
|
||||
final GitLineHandler h = createHandler(project, gitRoots, defaultRoot);
|
||||
if (h == null) {
|
||||
return;
|
||||
}
|
||||
@@ -63,34 +64,32 @@ public abstract class GitRebaseActionBase extends GitRepositoryAction {
|
||||
affectedRoots.add(root);
|
||||
|
||||
service.configureHandler(h, editor.getHandlerNo());
|
||||
GitTask task = new GitTask(project, h, GitBundle.getString("rebasing.title"));
|
||||
task.executeInBackground(false, new GitTaskResultHandlerAdapter() {
|
||||
new Task.Backgroundable(project, GitBundle.getString("rebasing.title"), false) {
|
||||
@Override
|
||||
protected void run(GitTaskResult taskResult) {
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
AccessToken token = DvcsUtil.workingTreeChangeStarted(project);
|
||||
try {
|
||||
GitCommandResult result = ServiceManager.getService(Git.class).runCommand(h);
|
||||
editor.close();
|
||||
GitRepositoryManager manager = GitUtil.getRepositoryManager(project);
|
||||
manager.updateRepository(root);
|
||||
root.refresh(false, true);
|
||||
notifyAboutResult(taskResult, resultListener, exceptions, project);
|
||||
notifyAboutResult(result, resultListener, exceptions, project);
|
||||
}
|
||||
finally {
|
||||
DvcsUtil.workingTreeChangeFinished(project, token);
|
||||
}
|
||||
}
|
||||
});
|
||||
}.queue();
|
||||
}
|
||||
|
||||
private static void notifyAboutResult(GitTaskResult taskResult,
|
||||
GitRebaseLineListener resultListener,
|
||||
List<VcsException> exceptions,
|
||||
Project project) {
|
||||
if (taskResult == GitTaskResult.CANCELLED) {
|
||||
return;
|
||||
}
|
||||
private static void notifyAboutResult(@NotNull GitCommandResult commandResult,
|
||||
@NotNull GitRebaseLineListener resultListener,
|
||||
@NotNull List<VcsException> exceptions,
|
||||
@NotNull Project project) {
|
||||
final GitRebaseLineListener.Result result = resultListener.getResult();
|
||||
String messageId;
|
||||
String message = null;
|
||||
boolean isError = true;
|
||||
switch (result.status) {
|
||||
case CONFLICT:
|
||||
@@ -98,6 +97,7 @@ public abstract class GitRebaseActionBase extends GitRepositoryAction {
|
||||
break;
|
||||
case ERROR:
|
||||
messageId = "rebase.result.error";
|
||||
message = commandResult.getErrorOutputAsHtmlString();
|
||||
break;
|
||||
case CANCELLED:
|
||||
// we do not need to show a message if editing was cancelled.
|
||||
@@ -112,18 +112,12 @@ public abstract class GitRebaseActionBase extends GitRepositoryAction {
|
||||
messageId = "rebase.result.success";
|
||||
break;
|
||||
default:
|
||||
messageId = null;
|
||||
throw new IllegalStateException("Unsupported rebase result: " + result.status);
|
||||
}
|
||||
|
||||
String message;
|
||||
String title;
|
||||
if (messageId != null) {
|
||||
String title = GitBundle.message(messageId + ".title");
|
||||
if (message == null) {
|
||||
message = GitBundle.message(messageId, result.current, result.total);
|
||||
title = GitBundle.message(messageId + ".title");
|
||||
}
|
||||
else {
|
||||
message = "Rebase finished: " + StringUtil.capitalize(StringUtil.toLowerCase(result.status.name()));
|
||||
title = "";
|
||||
}
|
||||
|
||||
if (isError) {
|
||||
|
||||
@@ -42,6 +42,14 @@ public interface Git {
|
||||
@NotNull
|
||||
GitCommandResult runCommand(@NotNull Computable<GitLineHandler> handlerConstructor);
|
||||
|
||||
/**
|
||||
* A generic method to run a Git command, when existing methods are not sufficient. <br/>
|
||||
* Can be used instead of {@link #runCommand(Computable)} if the operation will not need to be repeated for sure
|
||||
* (e.g. it is a completely local operation).
|
||||
*/
|
||||
@NotNull
|
||||
GitCommandResult runCommand(@NotNull GitLineHandler handler);
|
||||
|
||||
@NotNull
|
||||
GitCommandResult init(@NotNull Project project, @NotNull VirtualFile root, @NotNull GitLineHandlerListener... listeners);
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ import static java.util.Collections.singleton;
|
||||
*
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
@SuppressWarnings("StringToUpperCaseOrToLowerCaseWithoutLocale")
|
||||
public class GitImpl implements Git {
|
||||
|
||||
private final Logger LOG = Logger.getInstance(Git.class);
|
||||
@@ -624,13 +625,24 @@ public class GitImpl implements Git {
|
||||
public GitCommandResult runCommand(@NotNull Computable<GitLineHandler> handlerConstructor) {
|
||||
return run(handlerConstructor);
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult runCommand(@NotNull final GitLineHandler handler) {
|
||||
return runCommand(new Computable<GitLineHandler>() {
|
||||
@Override
|
||||
public GitLineHandler compute() {
|
||||
return handler;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the line looks line an error message
|
||||
*/
|
||||
private static boolean isError(String text) {
|
||||
for (String indicator : ERROR_INDICATORS) {
|
||||
if (text.startsWith(indicator.toLowerCase())) {
|
||||
if (text.trim().toLowerCase().startsWith(indicator.toLowerCase())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -640,7 +652,7 @@ public class GitImpl implements Git {
|
||||
// could be upper-cased, so should check case-insensitively
|
||||
public static final String[] ERROR_INDICATORS = {
|
||||
"error", "remote: error", "fatal",
|
||||
"Cannot apply", "Could not", "Interactive rebase already started", "refusing to pull", "cannot rebase:", "conflict",
|
||||
"Cannot", "Could not", "Interactive rebase already started", "refusing to pull", "cannot rebase:", "conflict",
|
||||
"unable"
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package git4idea.config;
|
||||
|
||||
import com.intellij.openapi.components.PersistentStateComponent;
|
||||
import com.intellij.openapi.components.State;
|
||||
import com.intellij.openapi.components.Storage;
|
||||
import com.intellij.openapi.components.StoragePathMacros;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@State(name = "Git.Rebase.Settings", storages = {@Storage(file = StoragePathMacros.WORKSPACE_FILE)})
|
||||
public class GitRebaseSettings implements PersistentStateComponent<GitRebaseSettings.State> {
|
||||
|
||||
private State myState = new State();
|
||||
|
||||
public static class State {
|
||||
public boolean INTERACTIVE = true;
|
||||
public boolean PRESERVE_MERGES = false;
|
||||
public boolean SHOW_TAGS = false;
|
||||
public boolean SHOW_REMOTE_BRANCHES = false;
|
||||
public String ONTO = null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public State getState() {
|
||||
return myState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadState(State state) {
|
||||
myState = state;
|
||||
}
|
||||
|
||||
public boolean isInteractive() {
|
||||
return myState.INTERACTIVE;
|
||||
}
|
||||
|
||||
public void setInteractive(boolean interactive) {
|
||||
myState.INTERACTIVE = interactive;
|
||||
}
|
||||
|
||||
public boolean isPreserveMerges() {
|
||||
return myState.PRESERVE_MERGES;
|
||||
}
|
||||
|
||||
public void setPreserveMerges(boolean preserveMerges) {
|
||||
myState.PRESERVE_MERGES = preserveMerges;
|
||||
}
|
||||
|
||||
public boolean showTags() {
|
||||
return myState.SHOW_TAGS;
|
||||
}
|
||||
|
||||
public void setShowTags(boolean showTags) {
|
||||
myState.SHOW_TAGS = showTags;
|
||||
}
|
||||
|
||||
public boolean showRemoteBranches() {
|
||||
return myState.SHOW_REMOTE_BRANCHES;
|
||||
}
|
||||
|
||||
public void setShowRemoteBranches(boolean showRemoteBranches) {
|
||||
myState.SHOW_REMOTE_BRANCHES = showRemoteBranches;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getOnto() {
|
||||
return myState.ONTO;
|
||||
}
|
||||
|
||||
public void setOnto(@Nullable String onto) {
|
||||
myState.ONTO = onto;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -290,7 +290,6 @@ rebase.result.cancelled=The rebase process was cancelled.
|
||||
rebase.result.conflict.title=Rebase Suspended
|
||||
rebase.result.conflict=Stopped rebasing because of conflict ({0}/{1}).\nResolve conflicts and continue the rebase process.
|
||||
rebase.result.error.title=Rebase Error
|
||||
rebase.result.error=Stopped rebasing because of error while rebasing ({0}/{1}).\nCheck vcs console for details.
|
||||
rebase.show.remote.branches.tooltip=If selected, remote branches are shown in drop down as well.
|
||||
rebase.show.remote.branches=Show Re&mote Branches
|
||||
rebase.show.tags.tooltip=Show tags in \"from\" and \"onto\" comboboxes.
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
*/
|
||||
package git4idea.rebase;
|
||||
|
||||
import com.intellij.CommonBundle;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
@@ -24,6 +26,7 @@ import git4idea.commands.GitHandler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The handler for rebase editor request. The handler shows {@link git4idea.rebase.GitRebaseEditor}
|
||||
@@ -110,21 +113,33 @@ public class GitInteractiveRebaseEditorHandler implements Closeable, GitRebaseEd
|
||||
isSuccess.set(true);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
isSuccess.set(false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
setRebaseEditorShown();
|
||||
GitRebaseEditor editor = new GitRebaseEditor(myProject, myRoot, path);
|
||||
if (editor.showAndGet()) {
|
||||
editor.save();
|
||||
isSuccess.set(true);
|
||||
return;
|
||||
GitInteractiveRebaseFile rebaseFile = new GitInteractiveRebaseFile(myProject, myRoot, path);
|
||||
try {
|
||||
List<GitRebaseEntry> entries = rebaseFile.load();
|
||||
GitRebaseEditor editor = new GitRebaseEditor(myProject, myRoot, entries);
|
||||
if (editor.showAndGet()) {
|
||||
rebaseFile.save(editor.getEntries());
|
||||
isSuccess.set(true);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
rebaseFile.cancel();
|
||||
}
|
||||
}
|
||||
else {
|
||||
editor.cancel();
|
||||
isSuccess.set(true);
|
||||
catch (GitInteractiveRebaseFile.NoopException e) {
|
||||
LOG.info("Noop situation while rebasing " + myRoot);
|
||||
String message = "There are no commits to rebase because the current branch is directly below the base branch " +
|
||||
"(the 'noop' situation).\n" +
|
||||
"Do you want to continue (this will reset the current branch to the base branch)?";
|
||||
int rebase = Messages.showOkCancelDialog(myProject, message, "Git Rebase", CommonBundle.getOkButtonText(),
|
||||
CommonBundle.getCancelButtonText(), Messages.getQuestionIcon());
|
||||
if (rebase == Messages.OK) {
|
||||
isSuccess.set(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package git4idea.rebase;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import git4idea.config.GitConfigUtil;
|
||||
import git4idea.util.StringScanner;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.List;
|
||||
|
||||
class GitInteractiveRebaseFile {
|
||||
@NonNls private static final String CYGDRIVE_PREFIX = "/cygdrive/";
|
||||
|
||||
@NotNull private final Project myProject;
|
||||
@NotNull private final VirtualFile myRoot;
|
||||
@NotNull private final String myFile;
|
||||
|
||||
GitInteractiveRebaseFile(@NotNull Project project, @NotNull VirtualFile root, @NotNull String rebaseFilePath) {
|
||||
myProject = project;
|
||||
myRoot = root;
|
||||
myFile = adjustFilePath(rebaseFilePath);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<GitRebaseEntry> load() throws IOException, NoopException {
|
||||
String encoding = GitConfigUtil.getLogEncoding(myProject, myRoot);
|
||||
List<GitRebaseEntry> entries = ContainerUtil.newArrayList();
|
||||
final StringScanner s = new StringScanner(FileUtil.loadFile(new File(myFile), encoding));
|
||||
boolean noop = false;
|
||||
while (s.hasMoreData()) {
|
||||
if (s.isEol() || s.startsWith('#')) {
|
||||
s.nextLine();
|
||||
continue;
|
||||
}
|
||||
if (s.startsWith("noop")) {
|
||||
noop = true;
|
||||
s.nextLine();
|
||||
continue;
|
||||
}
|
||||
String action = s.spaceToken();
|
||||
String hash = s.spaceToken();
|
||||
String comment = s.line();
|
||||
|
||||
entries.add(new GitRebaseEntry(action, hash, comment));
|
||||
}
|
||||
if (noop && entries.isEmpty()) {
|
||||
throw new NoopException();
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
public void cancel() throws IOException {
|
||||
PrintWriter out = new PrintWriter(new FileWriter(myFile));
|
||||
try {
|
||||
out.println("# rebase is cancelled");
|
||||
}
|
||||
finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void save(@NotNull List<GitRebaseEntry> entries) throws IOException {
|
||||
String encoding = GitConfigUtil.getLogEncoding(myProject, myRoot);
|
||||
PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(myFile), encoding));
|
||||
try {
|
||||
for (GitRebaseEntry e : entries) {
|
||||
if (e.getAction() != GitRebaseEntry.Action.skip) {
|
||||
out.println(e.getAction().toString() + " " + e.getCommit() + " " + e.getSubject());
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String adjustFilePath(@NotNull String file) {
|
||||
if (SystemInfo.isWindows && file.startsWith(CYGDRIVE_PREFIX)) {
|
||||
final int prefixSize = CYGDRIVE_PREFIX.length();
|
||||
return file.substring(prefixSize, prefixSize + 1) + ":" + file.substring(prefixSize + 1);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
static class NoopException extends Exception {
|
||||
}
|
||||
}
|
||||
@@ -15,10 +15,12 @@
|
||||
*/
|
||||
package git4idea.rebase;
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.ComboBox;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.DocumentAdapter;
|
||||
@@ -27,12 +29,15 @@ import git4idea.branch.GitBranchUtil;
|
||||
import git4idea.commands.GitCommand;
|
||||
import git4idea.commands.GitLineHandler;
|
||||
import git4idea.config.GitConfigUtil;
|
||||
import git4idea.config.GitRebaseSettings;
|
||||
import git4idea.i18n.GitBundle;
|
||||
import git4idea.merge.GitMergeUtil;
|
||||
import git4idea.repo.GitRemote;
|
||||
import git4idea.repo.GitRepository;
|
||||
import git4idea.ui.GitReferenceValidator;
|
||||
import git4idea.util.GitUIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
@@ -115,7 +120,7 @@ public class GitRebaseDialog extends DialogWrapper {
|
||||
/**
|
||||
* The current branch
|
||||
*/
|
||||
protected GitBranch myCurrentBranch;
|
||||
@Nullable protected GitBranch myCurrentBranch;
|
||||
/**
|
||||
* The tags
|
||||
*/
|
||||
@@ -128,6 +133,9 @@ public class GitRebaseDialog extends DialogWrapper {
|
||||
* The validator for from field
|
||||
*/
|
||||
private final GitReferenceValidator myFromValidator;
|
||||
@NotNull private final GitRebaseSettings mySettings;
|
||||
|
||||
@Nullable private final String myOriginalOntoBranch;
|
||||
|
||||
/**
|
||||
* A constructor
|
||||
@@ -142,6 +150,7 @@ public class GitRebaseDialog extends DialogWrapper {
|
||||
setOKButtonText(GitBundle.getString("rebase.button"));
|
||||
init();
|
||||
myProject = project;
|
||||
mySettings = ServiceManager.getService(myProject, GitRebaseSettings.class);
|
||||
final Runnable validateRunnable = new Runnable() {
|
||||
public void run() {
|
||||
validateFields();
|
||||
@@ -157,11 +166,50 @@ public class GitRebaseDialog extends DialogWrapper {
|
||||
validateFields();
|
||||
}
|
||||
});
|
||||
|
||||
setupBranches();
|
||||
setupStrategy();
|
||||
|
||||
myInteractiveCheckBox.setSelected(mySettings.isInteractive());
|
||||
myPreserveMergesCheckBox.setSelected(mySettings.isPreserveMerges());
|
||||
myShowTagsCheckBox.setSelected(mySettings.showTags());
|
||||
myShowRemoteBranchesCheckBox.setSelected(mySettings.showRemoteBranches());
|
||||
overwriteOntoForCurrentBranch(mySettings);
|
||||
|
||||
myOriginalOntoBranch = GitUIUtil.getTextField(myOntoComboBox).getText();
|
||||
|
||||
validateFields();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
return myOntoComboBox;
|
||||
}
|
||||
|
||||
private void overwriteOntoForCurrentBranch(@NotNull GitRebaseSettings settings) {
|
||||
String onto = settings.getOnto();
|
||||
if (onto != null && !onto.equals(myBranchComboBox.getSelectedItem())) {
|
||||
if (!isValidRevision(onto)) {
|
||||
mySettings.setOnto(null);
|
||||
}
|
||||
else {
|
||||
myOntoComboBox.setSelectedItem(onto);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidRevision(@NotNull String revisionExpression) {
|
||||
try {
|
||||
GitRevisionNumber.resolve(myProject, gitRoot(), revisionExpression);
|
||||
return true;
|
||||
}
|
||||
catch (VcsException e) {
|
||||
LOG.debug(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public GitLineHandler handler() {
|
||||
GitLineHandler h = new GitLineHandler(myProject, gitRoot(), GitCommand.REBASE);
|
||||
h.setStdoutSuppressed(false);
|
||||
@@ -195,6 +243,27 @@ public class GitRebaseDialog extends DialogWrapper {
|
||||
return h;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doOKAction() {
|
||||
try {
|
||||
rememberFields();
|
||||
}
|
||||
finally {
|
||||
super.doOKAction();
|
||||
}
|
||||
}
|
||||
|
||||
private void rememberFields() {
|
||||
mySettings.setInteractive(myInteractiveCheckBox.isSelected());
|
||||
mySettings.setPreserveMerges(myPreserveMergesCheckBox.isSelected());
|
||||
mySettings.setShowTags(myShowTagsCheckBox.isSelected());
|
||||
mySettings.setShowRemoteBranches(myShowRemoteBranchesCheckBox.isSelected());
|
||||
String onto = StringUtil.nullize(GitUIUtil.getTextField(myOntoComboBox).getText(), true);
|
||||
if (onto != null && !onto.equals(myOriginalOntoBranch)) {
|
||||
mySettings.setOnto(onto);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup strategy
|
||||
*/
|
||||
|
||||
@@ -17,12 +17,12 @@ package git4idea.rebase;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.Cell;
|
||||
import com.intellij.ui.ColoredTableCellRenderer;
|
||||
import com.intellij.ui.TableSpeedSearch;
|
||||
import com.intellij.ui.speedSearch.SpeedSearchUtil;
|
||||
import com.intellij.ui.table.JBTable;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.ListWithSelection;
|
||||
@@ -31,10 +31,8 @@ import com.intellij.util.ui.ComboBoxTableCellRenderer;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import git4idea.GitUtil;
|
||||
import git4idea.config.GitConfigUtil;
|
||||
import git4idea.i18n.GitBundle;
|
||||
import git4idea.util.StringScanner;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -46,8 +44,7 @@ import javax.swing.table.AbstractTableModel;
|
||||
import javax.swing.table.TableColumn;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -81,45 +78,21 @@ public class GitRebaseEditor extends DialogWrapper {
|
||||
* Table model
|
||||
*/
|
||||
private final MyTableModel myTableModel;
|
||||
/**
|
||||
* The file name
|
||||
*/
|
||||
private final String myFile;
|
||||
/**
|
||||
* The project
|
||||
*/
|
||||
private final Project myProject;
|
||||
/**
|
||||
* The git root
|
||||
*/
|
||||
private final VirtualFile myGitRoot;
|
||||
/**
|
||||
* The cygwin drive prefix
|
||||
*/
|
||||
@NonNls private static final String CYGDRIVE_PREFIX = "/cygdrive/";
|
||||
|
||||
/**
|
||||
* The constructor
|
||||
*
|
||||
* @param project the project
|
||||
* @param gitRoot the git root
|
||||
* @param file the file to edit
|
||||
* @param entries the file to edit
|
||||
* @throws IOException if file could not be loaded
|
||||
*/
|
||||
protected GitRebaseEditor(final Project project, final VirtualFile gitRoot, String file) throws IOException {
|
||||
protected GitRebaseEditor(final Project project, final VirtualFile gitRoot, List<GitRebaseEntry> entries) throws IOException {
|
||||
super(project, true);
|
||||
myProject = project;
|
||||
myGitRoot = gitRoot;
|
||||
setTitle(GitBundle.getString("rebase.editor.title"));
|
||||
setOKButtonText(GitBundle.getString("rebase.editor.button"));
|
||||
|
||||
if (SystemInfo.isWindows && file.startsWith(CYGDRIVE_PREFIX)) {
|
||||
final int prefixSize = CYGDRIVE_PREFIX.length();
|
||||
file = file.substring(prefixSize, prefixSize + 1) + ":" + file.substring(prefixSize + 1);
|
||||
}
|
||||
myFile = file;
|
||||
myTableModel = new MyTableModel();
|
||||
myTableModel.load(file);
|
||||
myTableModel = new MyTableModel(entries);
|
||||
myCommitsTable.setModel(myTableModel);
|
||||
myCommitsTable.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
|
||||
myCommitsTable.setIntercellSpacing(JBUI.emptySize());
|
||||
@@ -132,6 +105,14 @@ public class GitRebaseEditor extends DialogWrapper {
|
||||
actionColumn.setCellEditor(new DefaultCellEditor(editorComboBox));
|
||||
actionColumn.setCellRenderer(ComboBoxTableCellRenderer.INSTANCE);
|
||||
|
||||
myCommitsTable.setDefaultRenderer(String.class, new ColoredTableCellRenderer() {
|
||||
@Override
|
||||
protected void customizeCellRenderer(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
|
||||
append(value.toString());
|
||||
SpeedSearchUtil.applySpeedSearchHighlighting(myCommitsTable, this, true, selected);
|
||||
}
|
||||
});
|
||||
|
||||
myCommitsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
|
||||
public void valueChanged(final ListSelectionEvent e) {
|
||||
myViewButton.setEnabled(myCommitsTable.getSelectedRowCount() == 1);
|
||||
@@ -215,15 +196,6 @@ public class GitRebaseEditor extends DialogWrapper {
|
||||
setOKActionEnabled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save entries back to the file
|
||||
*
|
||||
* @throws IOException if there is IO problem with saving
|
||||
*/
|
||||
public void save() throws IOException {
|
||||
myTableModel.save(myFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@@ -247,13 +219,9 @@ public class GitRebaseEditor extends DialogWrapper {
|
||||
return "reference.VersionControl.Git.RebaseCommits";
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel rebase
|
||||
*
|
||||
* @throws IOException if file cannot be reset to empty one
|
||||
*/
|
||||
public void cancel() throws IOException {
|
||||
myTableModel.cancel(myFile);
|
||||
@NotNull
|
||||
public List<GitRebaseEntry> getEntries() {
|
||||
return myTableModel.myEntries;
|
||||
}
|
||||
|
||||
|
||||
@@ -274,12 +242,13 @@ public class GitRebaseEditor extends DialogWrapper {
|
||||
*/
|
||||
private static final int SUBJECT = 2;
|
||||
|
||||
/**
|
||||
* The entries
|
||||
*/
|
||||
final List<GitRebaseEntry> myEntries = new ArrayList<GitRebaseEntry>();
|
||||
@NotNull private final List<GitRebaseEntry> myEntries;
|
||||
private int[] myLastEditableSelectedRows = new int[]{};
|
||||
|
||||
MyTableModel(@NotNull List<GitRebaseEntry> entries) {
|
||||
myEntries = entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@@ -357,7 +326,7 @@ public class GitRebaseEditor extends DialogWrapper {
|
||||
}
|
||||
|
||||
private void setSelection(ContiguousIntIntervalTracker intervalBuilder) {
|
||||
myCommitsTable.getSelectionModel().setSelectionInterval( intervalBuilder.getMin() , intervalBuilder.getMax() );
|
||||
myCommitsTable.getSelectionModel().setSelectionInterval(intervalBuilder.getMin(), intervalBuilder.getMax());
|
||||
}
|
||||
|
||||
private void setRowAction(Object aValue, int rowIndex, int columnIndex) {
|
||||
@@ -375,66 +344,6 @@ public class GitRebaseEditor extends DialogWrapper {
|
||||
return columnIndex == ACTION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load data from the file
|
||||
*
|
||||
* @param file the file to load
|
||||
* @throws IOException if file could not be loaded
|
||||
*/
|
||||
public void load(final String file) throws IOException {
|
||||
String encoding = GitConfigUtil.getLogEncoding(myProject, myGitRoot);
|
||||
final StringScanner s = new StringScanner(FileUtil.loadFile(new File(file), encoding));
|
||||
while (s.hasMoreData()) {
|
||||
if (s.isEol() || s.startsWith('#') || s.startsWith("noop")) {
|
||||
s.nextLine();
|
||||
continue;
|
||||
}
|
||||
String action = s.spaceToken();
|
||||
String hash = s.spaceToken();
|
||||
String comment = s.line();
|
||||
myEntries.add(new GitRebaseEntry(action, hash, comment));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save text to the file
|
||||
*
|
||||
* @param file the file to save to
|
||||
* @throws IOException if there is IO problem
|
||||
*/
|
||||
public void save(final String file) throws IOException {
|
||||
String encoding = GitConfigUtil.getLogEncoding(myProject, myGitRoot);
|
||||
PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), encoding));
|
||||
try {
|
||||
for (GitRebaseEntry e : myEntries) {
|
||||
if (e.getAction() != GitRebaseEntry.Action.skip) {
|
||||
out.println(e.getAction().toString() + " " + e.getCommit() + " " + e.getSubject());
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save text to the file
|
||||
*
|
||||
* @param file the file to save to
|
||||
* @throws IOException if there is IO problem
|
||||
*/
|
||||
public void cancel(final String file) throws IOException {
|
||||
PrintWriter out = new PrintWriter(new FileWriter(file));
|
||||
try {
|
||||
//noinspection HardCodedStringLiteral
|
||||
out.println("# rebase is cancelled");
|
||||
}
|
||||
finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void moveRows(int[] rows, MoveDirection direction) {
|
||||
|
||||
myCommitsTable.removeEditor();
|
||||
|
||||
+10
-3
@@ -20,9 +20,11 @@ import com.intellij.openapi.options.Configurable;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.ui.RawCommandLineEditor;
|
||||
import com.intellij.ui.components.JBCheckBox;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.incremental.groovy.GreclipseSettings;
|
||||
|
||||
@@ -65,21 +67,26 @@ public class GreclipseConfigurable implements Configurable {
|
||||
|
||||
@Override
|
||||
public boolean isModified() {
|
||||
return !Comparing.equal(myJarPath.getText(), mySettings.greclipsePath) ||
|
||||
return !Comparing.equal(getExternalizableJarPath(), mySettings.greclipsePath) ||
|
||||
!Comparing.equal(myCmdLineParams.getText(), mySettings.cmdLineParams) ||
|
||||
!Comparing.equal(myGenerateDebugInfo.isSelected(), mySettings.debugInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply() throws ConfigurationException {
|
||||
mySettings.greclipsePath = myJarPath.getText();
|
||||
mySettings.greclipsePath = getExternalizableJarPath();
|
||||
mySettings.cmdLineParams = myCmdLineParams.getText();
|
||||
mySettings.debugInfo = myGenerateDebugInfo.isSelected();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getExternalizableJarPath() {
|
||||
return FileUtil.toSystemIndependentName(myJarPath.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
myJarPath.setText(mySettings.greclipsePath);
|
||||
myJarPath.setText(FileUtil.toSystemDependentName(mySettings.greclipsePath));
|
||||
myCmdLineParams.setText(mySettings.cmdLineParams);
|
||||
myGenerateDebugInfo.setSelected(mySettings.debugInfo);
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
<reference ref="Annotate"/>
|
||||
<separator/>
|
||||
|
||||
<action id="hg4idea.pull" class="org.zmlx.hg4idea.action.HgPullAction"/>
|
||||
<action id="hg4idea.pull" class="org.zmlx.hg4idea.action.HgPullAction" icon="AllIcons.Actions.CheckOut"/>
|
||||
<reference ref="Vcs.Push"/>
|
||||
<separator/>
|
||||
<action id="hg4idea.run.conflict.resolver" class="org.zmlx.hg4idea.action.HgRunConflictResolverAction"/>
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
// limitations under the License.
|
||||
package org.zmlx.hg4idea.action;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -25,19 +25,12 @@ import org.zmlx.hg4idea.repo.HgRepository;
|
||||
import org.zmlx.hg4idea.repo.HgRepositoryManager;
|
||||
import org.zmlx.hg4idea.util.HgUtil;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class HgAbstractGlobalAction extends AnAction {
|
||||
protected HgAbstractGlobalAction(Icon icon) {
|
||||
super(icon);
|
||||
}
|
||||
|
||||
protected HgAbstractGlobalAction() {
|
||||
}
|
||||
public abstract class HgAbstractGlobalAction extends DumbAwareAction {
|
||||
|
||||
public void actionPerformed(@NotNull AnActionEvent event) {
|
||||
final DataContext dataContext = event.getDataContext();
|
||||
@@ -82,5 +75,4 @@ public abstract class HgAbstractGlobalAction extends AnAction {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,20 +20,11 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.zmlx.hg4idea.repo.HgRepository;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class HgAbstractGlobalSingleRepoAction extends HgAbstractGlobalAction {
|
||||
|
||||
public HgAbstractGlobalSingleRepoAction(Icon icon) {
|
||||
super(icon);
|
||||
}
|
||||
|
||||
public HgAbstractGlobalSingleRepoAction() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(@NotNull Project project,
|
||||
@NotNull Collection<HgRepository> repositories,
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
// limitations under the License.
|
||||
package org.zmlx.hg4idea.action;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -26,9 +25,6 @@ import org.zmlx.hg4idea.util.HgErrorUtil;
|
||||
import java.util.Collection;
|
||||
|
||||
public class HgPullAction extends HgAbstractGlobalSingleRepoAction {
|
||||
public HgPullAction() {
|
||||
super(AllIcons.Actions.CheckOut);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(@NotNull final Project project, @NotNull Collection<HgRepository> repos, @Nullable HgRepository selectedRepo) {
|
||||
|
||||
@@ -16,12 +16,6 @@ import com.intellij.dvcs.DvcsUtil;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.FileEditor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.fileEditor.TextEditor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.Couple;
|
||||
@@ -38,9 +32,6 @@ import com.intellij.openapi.vfs.CharsetToolkit;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.wm.StatusBar;
|
||||
import com.intellij.openapi.wm.WindowManager;
|
||||
import com.intellij.openapi.wm.impl.status.StatusBarUtil;
|
||||
import com.intellij.ui.GuiUtils;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -284,36 +275,9 @@ public abstract class HgUtil {
|
||||
return getHgRootOrThrow(project, VcsUtil.getFilePath(file.getPath()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently selected file, based on which HgBranch components will identify the current repository root.
|
||||
*/
|
||||
@Nullable
|
||||
public static VirtualFile getSelectedFile(@NotNull Project project) {
|
||||
StatusBar statusBar = WindowManager.getInstance().getStatusBar(project);
|
||||
final FileEditor fileEditor = StatusBarUtil.getCurrentFileEditor(project, statusBar);
|
||||
VirtualFile result = null;
|
||||
if (fileEditor != null) {
|
||||
if (fileEditor instanceof TextEditor) {
|
||||
Document document = ((TextEditor)fileEditor).getEditor().getDocument();
|
||||
result = FileDocumentManager.getInstance().getFile(document);
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
final FileEditorManager manager = FileEditorManager.getInstance(project);
|
||||
if (manager != null) {
|
||||
Editor editor = manager.getSelectedTextEditor();
|
||||
if (editor != null) {
|
||||
result = FileDocumentManager.getInstance().getFile(editor.getDocument());
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static VirtualFile getRootForSelectedFile(@NotNull Project project) {
|
||||
VirtualFile selectedFile = getSelectedFile(project);
|
||||
VirtualFile selectedFile = DvcsUtil.getSelectedFile(project);
|
||||
if (selectedFile != null) {
|
||||
return getHgRootOrNull(project, selectedFile);
|
||||
}
|
||||
|
||||
@@ -17,10 +17,7 @@
|
||||
package com.intellij.execution.junit;
|
||||
|
||||
import com.intellij.execution.*;
|
||||
import com.intellij.execution.configurations.JavaParameters;
|
||||
import com.intellij.execution.configurations.ParametersList;
|
||||
import com.intellij.execution.configurations.RunnerSettings;
|
||||
import com.intellij.execution.configurations.RuntimeConfigurationException;
|
||||
import com.intellij.execution.configurations.*;
|
||||
import com.intellij.execution.junit2.TestProxy;
|
||||
import com.intellij.execution.junit2.segments.DeferredActionsQueue;
|
||||
import com.intellij.execution.junit2.segments.DeferredActionsQueueImpl;
|
||||
@@ -33,8 +30,7 @@ import com.intellij.execution.junit2.ui.model.CompletionEvent;
|
||||
import com.intellij.execution.junit2.ui.model.JUnitRunningModel;
|
||||
import com.intellij.execution.junit2.ui.model.RootTestInfo;
|
||||
import com.intellij.execution.junit2.ui.properties.JUnitConsoleProperties;
|
||||
import com.intellij.execution.process.ProcessAdapter;
|
||||
import com.intellij.execution.process.ProcessEvent;
|
||||
import com.intellij.execution.process.*;
|
||||
import com.intellij.execution.runners.ExecutionEnvironment;
|
||||
import com.intellij.execution.runners.ProgramRunner;
|
||||
import com.intellij.execution.testframework.*;
|
||||
@@ -173,7 +169,7 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
if (executionResult != null) {
|
||||
return executionResult;
|
||||
}
|
||||
final JUnitProcessHandler handler = createHandler(executor);
|
||||
final JUnitProcessHandler handler = createJUnitHandler(executor);
|
||||
final RunnerSettings runnerSettings = getRunnerSettings();
|
||||
JavaRunConfigurationExtensionManager.getInstance().attachExtensionsToProcess(getConfiguration(), handler, runnerSettings);
|
||||
final TestProxy unboundOutputRoot = new TestProxy(new RootTestInfo());
|
||||
@@ -284,7 +280,7 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected JUnitProcessHandler createHandler(Executor executor) throws ExecutionException {
|
||||
protected JUnitProcessHandler createJUnitHandler(Executor executor) throws ExecutionException {
|
||||
appendForkInfo(executor);
|
||||
final String repeatMode = getConfiguration().getRepeatMode();
|
||||
if (!RepeatCount.ONCE.equals(repeatMode)) {
|
||||
@@ -297,6 +293,27 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
|
||||
return JUnitProcessHandler.runCommandLine(createCommandLine());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected OSProcessHandler createHandler(Executor executor) throws ExecutionException {
|
||||
appendForkInfo(executor);
|
||||
final String repeatMode = getConfiguration().getRepeatMode();
|
||||
if (!RepeatCount.ONCE.equals(repeatMode)) {
|
||||
final int repeatCount = getConfiguration().getRepeatCount();
|
||||
final String countString = RepeatCount.N.equals(repeatMode) && repeatCount > 0
|
||||
? RepeatCount.getCountString(repeatCount)
|
||||
: repeatMode;
|
||||
getJavaParameters().getProgramParametersList().add(countString);
|
||||
}
|
||||
|
||||
final OSProcessHandler processHandler = new KillableColoredProcessHandler(createCommandLine());
|
||||
ProcessTerminatedListener.attach(processHandler);
|
||||
final SearchForTestsTask searchForTestsTask = createSearchingForTestsTask();
|
||||
if (searchForTestsTask != null) {
|
||||
searchForTestsTask.attachTaskToProcess(processHandler);
|
||||
}
|
||||
return processHandler;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected SMTRunnerConsoleProperties createTestConsoleProperties(Executor executor) {
|
||||
|
||||
@@ -60,8 +60,8 @@ public class TestPackage extends TestObject {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected JUnitProcessHandler createHandler(Executor executor) throws ExecutionException {
|
||||
final JUnitProcessHandler handler = super.createHandler(executor);
|
||||
protected JUnitProcessHandler createJUnitHandler(Executor executor) throws ExecutionException {
|
||||
final JUnitProcessHandler handler = super.createJUnitHandler(executor);
|
||||
createSearchingForTestsTask().attachTaskToProcess(handler);
|
||||
return handler;
|
||||
}
|
||||
|
||||
+2
-1
@@ -18,6 +18,7 @@ package org.jetbrains.jps.maven.compiler;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.Base64;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.builders.storage.BuildDataPaths;
|
||||
@@ -58,7 +59,7 @@ public class MavenCommonArtifactRootCopyingHandlerProvider extends ArtifactRootC
|
||||
projectConfiguration.moduleConfigurations.get(getModuleName(artifact.getName()));
|
||||
if (moduleResourceConfiguration != null && moduleResourceConfiguration.manifest != null) {
|
||||
try {
|
||||
FileUtil.writeToFile(root, moduleResourceConfiguration.manifest);
|
||||
FileUtil.writeToFile(root, Base64.decode(moduleResourceConfiguration.manifest));
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.debug(e);
|
||||
|
||||
+8
-2
@@ -14,15 +14,20 @@ import com.intellij.openapi.util.JDOMUtil;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.io.StreamUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Base64;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.xmlb.XmlSerializer;
|
||||
import org.jdom.Document;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.maven.dom.MavenDomUtil;
|
||||
import org.jetbrains.idea.maven.dom.MavenPropertyResolver;
|
||||
import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel;
|
||||
import org.jetbrains.idea.maven.dom.references.MavenFilteredPropertyPsiReferenceProvider;
|
||||
import org.jetbrains.idea.maven.model.MavenId;
|
||||
import org.jetbrains.idea.maven.model.MavenResource;
|
||||
@@ -222,8 +227,9 @@ public class MavenResourceCompilerConfigurationGenerator {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
try {
|
||||
manifest.write(outputStream);
|
||||
resourceConfig.manifest = outputStream.toString("UTF8");
|
||||
|
||||
MavenDomProjectModel domModel = MavenDomUtil.getMavenDomProjectModel(module.getProject(), mavenProject.getFile());
|
||||
final String resolvedText = MavenPropertyResolver.resolve(outputStream.toString(CharsetToolkit.UTF8), domModel);
|
||||
resourceConfig.manifest = Base64.encode(resolvedText.getBytes(CharsetToolkit.UTF8));
|
||||
}
|
||||
finally {
|
||||
StreamUtil.closeStream(outputStream);
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
@@ -53,7 +53,7 @@ public abstract class TaskRepositoryType<T extends TaskRepository> implements Ta
|
||||
public abstract TaskRepositoryEditor createEditor(T repository, Project project, Consumer<T> changeListener);
|
||||
|
||||
public List<TaskRepositorySubtype> getAvailableSubtypes() {
|
||||
return Arrays.asList((TaskRepositorySubtype)this);
|
||||
return Collections.singletonList((TaskRepositorySubtype)this);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -15,49 +15,21 @@
|
||||
*/
|
||||
package com.intellij.tasks.jira.jql;
|
||||
|
||||
import com.intellij.extapi.psi.ASTWrapperPsiElement;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
/**
|
||||
* @author Mikhail Golubev
|
||||
*/
|
||||
public class JqlElementType extends IElementType {
|
||||
private static final Class<?>[] PARAMETER_TYPES = {ASTNode.class};
|
||||
|
||||
private final Class<? extends PsiElement> myClass;
|
||||
private Constructor<? extends PsiElement> myConstructor;
|
||||
|
||||
public JqlElementType(@NotNull @NonNls String debugName) {
|
||||
this(debugName, ASTWrapperPsiElement.class);
|
||||
}
|
||||
|
||||
public JqlElementType(@NotNull @NonNls String debugName, @NotNull Class<? extends PsiElement> cls) {
|
||||
super(debugName, JqlLanguage.INSTANCE);
|
||||
myClass = cls;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JQL: " + super.toString();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiElement createElement(@NotNull ASTNode node) {
|
||||
try {
|
||||
if (myConstructor == null) {
|
||||
myConstructor = myClass.getConstructor(PARAMETER_TYPES);
|
||||
}
|
||||
return myConstructor.newInstance(node);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AssertionError(
|
||||
String.format("Class %s must have constructor accepting single ASTNode parameter", myClass.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+80
-17
@@ -1,9 +1,13 @@
|
||||
package com.intellij.tasks.jira.jql;
|
||||
|
||||
import com.intellij.extapi.psi.ASTWrapperPsiElement;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.IFileElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.tasks.jira.jql.psi.impl.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Mikhail Golubev
|
||||
@@ -69,30 +73,89 @@ import com.intellij.tasks.jira.jql.psi.impl.*;
|
||||
*/
|
||||
public interface JqlElementTypes {
|
||||
IFileElementType FILE = new IFileElementType(JqlLanguage.INSTANCE);
|
||||
IElementType QUERY = new JqlElementType("QUERY", JqlQueryImpl.class);
|
||||
IElementType OR_CLAUSE = new JqlElementType("OR_CLAUSE", JqlOrClauseImpl.class);
|
||||
IElementType AND_CLAUSE = new JqlElementType("AND_CLAUSE", JqlAndClauseImpl.class);
|
||||
IElementType NOT_CLAUSE = new JqlElementType("NOT_CLAUSE", JqlNotClauseImpl.class);
|
||||
IElementType QUERY = new JqlElementType("QUERY");
|
||||
IElementType OR_CLAUSE = new JqlElementType("OR_CLAUSE");
|
||||
IElementType AND_CLAUSE = new JqlElementType("AND_CLAUSE");
|
||||
IElementType NOT_CLAUSE = new JqlElementType("NOT_CLAUSE");
|
||||
// actually parenthesized clause, named so to be consistent with official grammar
|
||||
IElementType SUB_CLAUSE = new JqlElementType("SUB_CLAUSE", JqlSubClauseImpl.class);
|
||||
IElementType SUB_CLAUSE = new JqlElementType("SUB_CLAUSE");
|
||||
//IElementType TERMINAL_CLAUSE = new JqlElementType("TERMINAL_CLAUSE");
|
||||
// field (= | != | ~ | !~ | < | > | <= | >= | is [not] | [not] in) value
|
||||
IElementType SIMPLE_CLAUSE = new JqlElementType("SIMPLE_CLAUSE", JqlSimpleClauseImpl.class);
|
||||
IElementType SIMPLE_CLAUSE = new JqlElementType("SIMPLE_CLAUSE");
|
||||
// field was [not] [in] value {history_predicate}
|
||||
IElementType WAS_CLAUSE = new JqlElementType("WAS_CLAUSE", JqlWasClauseImpl.class);
|
||||
IElementType WAS_CLAUSE = new JqlElementType("WAS_CLAUSE");
|
||||
// field changed {history_predicate}
|
||||
IElementType CHANGED_CLAUSE = new JqlElementType("CHANGED_CLAUSE", JqlChangedClauseImpl.class);
|
||||
IElementType LIST = new JqlElementType("LIST", JqlListImpl.class);
|
||||
IElementType ORDER_BY = new JqlElementType("ORDER_BY", JqlOrderByImpl.class);
|
||||
IElementType IDENTIFIER = new JqlElementType("IDENTIFIER", JqlIdentifierImpl.class);
|
||||
IElementType LITERAL = new JqlElementType("LITERAL", JqlLiteralImpl.class);
|
||||
IElementType FUNCTION_CALL = new JqlElementType("FUNCTION_CALL", JqlFunctionCallImpl.class);
|
||||
IElementType ARGUMENT_LIST = new JqlElementType("ARGUMENT_LIST", JqlArgumentListImpl.class);
|
||||
IElementType SORT_KEY = new JqlElementType("SORT_KEY", JqlSortKeyImpl.class);
|
||||
IElementType EMPTY = new JqlElementType("EMPTY", JqlEmptyValueImpl.class);
|
||||
IElementType HISTORY_PREDICATE = new JqlElementType("HISTORY_PREDICATE", JqlHistoryPredicateImpl.class);
|
||||
IElementType CHANGED_CLAUSE = new JqlElementType("CHANGED_CLAUSE");
|
||||
IElementType LIST = new JqlElementType("LIST");
|
||||
IElementType ORDER_BY = new JqlElementType("ORDER_BY");
|
||||
IElementType IDENTIFIER = new JqlElementType("IDENTIFIER");
|
||||
IElementType LITERAL = new JqlElementType("LITERAL");
|
||||
IElementType FUNCTION_CALL = new JqlElementType("FUNCTION_CALL");
|
||||
IElementType ARGUMENT_LIST = new JqlElementType("ARGUMENT_LIST");
|
||||
IElementType SORT_KEY = new JqlElementType("SORT_KEY");
|
||||
IElementType EMPTY = new JqlElementType("EMPTY");
|
||||
IElementType HISTORY_PREDICATE = new JqlElementType("HISTORY_PREDICATE");
|
||||
|
||||
TokenSet OPERAND_NODES = TokenSet.create(
|
||||
JqlTokenTypes.NUMBER_LITERAL, JqlTokenTypes.STRING_LITERAL, LIST, FUNCTION_CALL, EMPTY
|
||||
);
|
||||
|
||||
class Factory {
|
||||
@NotNull
|
||||
public static PsiElement createElement(@NotNull ASTNode node) {
|
||||
final IElementType type = node.getElementType();
|
||||
if (type == QUERY) {
|
||||
return new JqlQueryImpl(node);
|
||||
}
|
||||
else if (type == OR_CLAUSE) {
|
||||
return new JqlOrClauseImpl(node);
|
||||
}
|
||||
else if (type == AND_CLAUSE) {
|
||||
return new JqlAndClauseImpl(node);
|
||||
}
|
||||
else if (type == NOT_CLAUSE) {
|
||||
return new JqlNotClauseImpl(node);
|
||||
}
|
||||
else if (type == SUB_CLAUSE) {
|
||||
return new JqlSubClauseImpl(node);
|
||||
}
|
||||
else if (type == SIMPLE_CLAUSE) {
|
||||
return new JqlSimpleClauseImpl(node);
|
||||
}
|
||||
else if (type == WAS_CLAUSE) {
|
||||
return new JqlWasClauseImpl(node);
|
||||
}
|
||||
else if (type == CHANGED_CLAUSE) {
|
||||
return new JqlChangedClauseImpl(node);
|
||||
}
|
||||
else if (type == LIST) {
|
||||
return new JqlListImpl(node);
|
||||
}
|
||||
else if (type == ORDER_BY) {
|
||||
return new JqlOrderByImpl(node);
|
||||
}
|
||||
else if (type == IDENTIFIER) {
|
||||
return new JqlIdentifierImpl(node);
|
||||
}
|
||||
else if (type == LITERAL) {
|
||||
return new JqlLiteralImpl(node);
|
||||
}
|
||||
else if (type == FUNCTION_CALL) {
|
||||
return new JqlFunctionCallImpl(node);
|
||||
}
|
||||
else if (type == ARGUMENT_LIST) {
|
||||
return new JqlArgumentListImpl(node);
|
||||
}
|
||||
else if (type == SORT_KEY) {
|
||||
return new JqlSortKeyImpl(node);
|
||||
}
|
||||
else if (type == EMPTY) {
|
||||
return new JqlEmptyValueImpl(node);
|
||||
}
|
||||
else if (type == HISTORY_PREDICATE) {
|
||||
return new JqlHistoryPredicateImpl(node);
|
||||
}
|
||||
return new ASTWrapperPsiElement(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-7
@@ -1,6 +1,5 @@
|
||||
package com.intellij.tasks.jira.jql;
|
||||
|
||||
import com.intellij.extapi.psi.ASTWrapperPsiElement;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.ParserDefinition;
|
||||
import com.intellij.lang.PsiParser;
|
||||
@@ -10,7 +9,6 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.FileViewProvider;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.IFileElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -58,11 +56,7 @@ public class JqlParserDefinition implements ParserDefinition {
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElement createElement(ASTNode node) {
|
||||
final IElementType type = node.getElementType();
|
||||
if (type instanceof JqlElementType) {
|
||||
return ((JqlElementType)type).createElement(node);
|
||||
}
|
||||
return new ASTWrapperPsiElement(node);
|
||||
return JqlElementTypes.Factory.createElement(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+13
-354
@@ -20,40 +20,31 @@
|
||||
*/
|
||||
package com.theoryinpractice.testng.configuration;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.execution.CantRunException;
|
||||
import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.testframework.SearchForTestsTask;
|
||||
import com.intellij.execution.testframework.TestSearchScope;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.PackageScope;
|
||||
import com.intellij.psi.search.searches.AnnotatedMembersSearch;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.util.ClassUtil;
|
||||
import com.theoryinpractice.testng.model.IDEARemoteTestRunnerClient;
|
||||
import com.theoryinpractice.testng.model.TestClassFilter;
|
||||
import com.theoryinpractice.testng.model.TestData;
|
||||
import com.theoryinpractice.testng.model.TestNGTestObject;
|
||||
import com.theoryinpractice.testng.model.TestType;
|
||||
import com.theoryinpractice.testng.util.TestNGUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.testng.xml.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
public class SearchingForTestsTask extends SearchForTestsTask {
|
||||
private static final Logger LOG = Logger.getInstance("#" + SearchingForTestsTask.class.getName());
|
||||
@@ -233,14 +224,12 @@ public class SearchingForTestsTask extends SearchForTestsTask {
|
||||
}
|
||||
|
||||
private boolean shouldSearchForTestMethods() {
|
||||
boolean dependantMethods = false;
|
||||
for (Map<PsiMethod, List<String>> methods : myClasses.values()) {
|
||||
if (!methods.isEmpty()) {
|
||||
dependantMethods = true;
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return dependantMethods;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void composeTestSuiteFromXml() throws CantRunException {
|
||||
@@ -280,182 +269,9 @@ public class SearchingForTestsTask extends SearchForTestsTask {
|
||||
|
||||
protected void fillTestObjects(final Map<PsiClass, Map<PsiMethod, List<String>>> classes)
|
||||
throws CantRunException {
|
||||
final TestData data = myConfig.getPersistantData();
|
||||
final PsiManager psiManager = PsiManager.getInstance(myProject);
|
||||
if (data.TEST_OBJECT.equals(TestType.PACKAGE.getType())) {
|
||||
final String packageName = data.getPackageName();
|
||||
PsiPackage psiPackage = ApplicationManager.getApplication().runReadAction(
|
||||
new Computable<PsiPackage>() {
|
||||
@Nullable
|
||||
public PsiPackage compute() {
|
||||
return JavaPsiFacade.getInstance(psiManager.getProject()).findPackage(packageName);
|
||||
}
|
||||
}
|
||||
);
|
||||
if (psiPackage == null) {
|
||||
throw CantRunException.packageNotFound(packageName);
|
||||
}
|
||||
else {
|
||||
TestSearchScope scope = myConfig.getPersistantData().getScope();
|
||||
//TODO we should narrow this down by module really, if that's what's specified
|
||||
TestClassFilter projectFilter =
|
||||
new TestClassFilter(scope.getSourceScope(myConfig).getGlobalSearchScope(), myProject, true, true);
|
||||
TestClassFilter filter = projectFilter.intersectionWith(PackageScope.packageScope(psiPackage, true));
|
||||
calculateDependencies(null, classes, TestNGUtil.getAllTestClasses(filter, false));
|
||||
if (classes.size() == 0) {
|
||||
throw new CantRunException("No tests found in the package \"" + packageName + '\"');
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (data.TEST_OBJECT.equals(TestType.CLASS.getType())) {
|
||||
//it's a class
|
||||
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(
|
||||
new Computable<PsiClass>() {
|
||||
@Nullable
|
||||
public PsiClass compute() {
|
||||
return ClassUtil.findPsiClass(psiManager, data.getMainClassName().replace('/', '.'), null, true, getSearchScope());
|
||||
}
|
||||
}
|
||||
);
|
||||
if (psiClass == null) {
|
||||
throw new CantRunException("No tests found in the class \"" + data.getMainClassName() + '\"');
|
||||
}
|
||||
if (null == ApplicationManager.getApplication().runReadAction(new Computable<String>() {
|
||||
@Nullable
|
||||
public String compute() {
|
||||
return psiClass.getQualifiedName();
|
||||
}
|
||||
})) {
|
||||
throw new CantRunException("Cannot test anonymous or local class \"" + data.getMainClassName() + '\"');
|
||||
}
|
||||
calculateDependencies(null, classes, psiClass);
|
||||
}
|
||||
else if (data.TEST_OBJECT.equals(TestType.METHOD.getType())) {
|
||||
//it's a method
|
||||
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(
|
||||
new Computable<PsiClass>() {
|
||||
@Nullable
|
||||
public PsiClass compute() {
|
||||
return ClassUtil.findPsiClass(psiManager, data.getMainClassName().replace('/', '.'), null, true, getSearchScope());
|
||||
}
|
||||
}
|
||||
);
|
||||
if (psiClass == null) {
|
||||
throw new CantRunException("No tests found in the class \"" + data.getMainClassName() + '\"');
|
||||
}
|
||||
if (null == ApplicationManager.getApplication().runReadAction(
|
||||
new Computable<String>() {
|
||||
@Nullable
|
||||
public String compute() {
|
||||
return psiClass.getQualifiedName();
|
||||
}
|
||||
}
|
||||
)) {
|
||||
throw new CantRunException("Cannot test anonymous or local class \"" + data.getMainClassName() + '\"');
|
||||
}
|
||||
collectTestMethods(classes, psiClass, data.getMethodName());
|
||||
}
|
||||
else if (data.TEST_OBJECT.equals(TestType.GROUP.getType())) {
|
||||
//for a group, we include all classes
|
||||
PsiClass[] testClasses = TestNGUtil
|
||||
.getAllTestClasses(new TestClassFilter(data.getScope().getSourceScope(myConfig).getGlobalSearchScope(), myProject, true, true), false);
|
||||
if (testClasses != null) {
|
||||
for (PsiClass c : testClasses) {
|
||||
classes.put(c, new LinkedHashMap<PsiMethod, List<String>>());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (data.TEST_OBJECT.equals(TestType.PATTERN.getType())) {
|
||||
for (final String pattern : data.getPatterns()) {
|
||||
final String className;
|
||||
final String methodName;
|
||||
if (pattern.contains(",")) {
|
||||
methodName = StringUtil.getShortName(pattern, ',');
|
||||
className = StringUtil.getPackageName(pattern, ',');
|
||||
} else {
|
||||
className = pattern;
|
||||
methodName = null;
|
||||
}
|
||||
|
||||
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiClass compute() {
|
||||
return ClassUtil.findPsiClass(psiManager, className.replace('/', '.'), null, true, getSearchScope());
|
||||
}
|
||||
});
|
||||
if (psiClass != null) {
|
||||
final Boolean hasTest = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
|
||||
@Override
|
||||
public Boolean compute() {
|
||||
return TestNGUtil.hasTest(psiClass);
|
||||
}
|
||||
});
|
||||
if (hasTest) {
|
||||
if (StringUtil.isEmpty(methodName)) {
|
||||
calculateDependencies(null, classes, psiClass);
|
||||
}
|
||||
else {
|
||||
collectTestMethods(classes, psiClass, methodName);
|
||||
}
|
||||
} else {
|
||||
throw new CantRunException("No tests found in class " + className);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (classes.size() != data.getPatterns().size()) {
|
||||
TestSearchScope scope = myConfig.getPersistantData().getScope();
|
||||
final List<Pattern> compilePatterns = new ArrayList<Pattern>();
|
||||
for (String p : data.getPatterns()) {
|
||||
final Pattern compilePattern;
|
||||
try {
|
||||
compilePattern = Pattern.compile(p);
|
||||
}
|
||||
catch (PatternSyntaxException e) {
|
||||
continue;
|
||||
}
|
||||
if (compilePattern != null) {
|
||||
compilePatterns.add(compilePattern);
|
||||
}
|
||||
}
|
||||
TestClassFilter projectFilter =
|
||||
new TestClassFilter(scope.getSourceScope(myConfig).getGlobalSearchScope(), myProject, true, true){
|
||||
@Override
|
||||
public boolean isAccepted(PsiClass psiClass) {
|
||||
if (super.isAccepted(psiClass)) {
|
||||
final String qualifiedName = psiClass.getQualifiedName();
|
||||
LOG.assertTrue(qualifiedName != null);
|
||||
for (Pattern pattern : compilePatterns) {
|
||||
if (pattern.matcher(qualifiedName).matches()) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
calculateDependencies(null, classes, TestNGUtil.getAllTestClasses(projectFilter, false));
|
||||
if (classes.size() == 0) {
|
||||
throw new CantRunException("No tests found in for patterns \"" + StringUtil.join(data.getPatterns(), " || ") + '\"');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void collectTestMethods(Map<PsiClass, Map<PsiMethod, List<String>>> classes, final PsiClass psiClass, final String methodName) {
|
||||
final PsiMethod[] methods = ApplicationManager.getApplication().runReadAction(
|
||||
new Computable<PsiMethod[]>() {
|
||||
public PsiMethod[] compute() {
|
||||
return psiClass.findMethodsByName(methodName, true);
|
||||
}
|
||||
}
|
||||
);
|
||||
calculateDependencies(methods, classes, psiClass);
|
||||
Map<PsiMethod, List<String>> psiMethods = classes.get(psiClass);
|
||||
if (psiMethods == null) {
|
||||
psiMethods = new LinkedHashMap<PsiMethod, List<String>>();
|
||||
classes.put(psiClass, psiMethods);
|
||||
}
|
||||
for (PsiMethod method : methods) {
|
||||
psiMethods.put(method, Collections.<String>emptyList());
|
||||
final TestNGTestObject testObject = TestNGTestObject.fromConfig(myConfig);
|
||||
if (testObject != null) {
|
||||
testObject.fillTestObjects(classes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,24 +279,15 @@ public class SearchingForTestsTask extends SearchForTestsTask {
|
||||
Map<String, String> testParams = new HashMap<String, String>();
|
||||
|
||||
// Override with those from the test runner configuration
|
||||
testParams.putAll(convertPropertiesFileToMap(myData.PROPERTIES_FILE));
|
||||
testParams.putAll(myData.TEST_PROPERTIES);
|
||||
|
||||
return testParams;
|
||||
}
|
||||
|
||||
private static Map<String, String> convertPropertiesFileToMap(String properties_file) {
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
|
||||
if (properties_file != null) {
|
||||
File propertiesFile = new File(properties_file);
|
||||
if (myData.PROPERTIES_FILE != null) {
|
||||
File propertiesFile = new File(myData.PROPERTIES_FILE);
|
||||
if (propertiesFile.exists()) {
|
||||
|
||||
Properties properties = new Properties();
|
||||
try {
|
||||
properties.load(new FileInputStream(propertiesFile));
|
||||
for (Map.Entry entry : properties.entrySet()) {
|
||||
params.put((String)entry.getKey(), (String)entry.getValue());
|
||||
testParams.put((String)entry.getKey(), (String)entry.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -489,155 +296,7 @@ public class SearchingForTestsTask extends SearchForTestsTask {
|
||||
}
|
||||
}
|
||||
}
|
||||
return params;
|
||||
testParams.putAll(myData.TEST_PROPERTIES);
|
||||
return testParams;
|
||||
}
|
||||
|
||||
private void calculateDependencies(PsiMethod[] methods,
|
||||
final Map<PsiClass, Map<PsiMethod, List<String>>> results,
|
||||
@Nullable final PsiClass... classes) {
|
||||
calculateDependencies(methods, results, new LinkedHashSet<PsiMember>(), classes);
|
||||
}
|
||||
|
||||
private void calculateDependencies(final PsiMethod[] methods,
|
||||
final Map<PsiClass, Map<PsiMethod, List<String>>> results,
|
||||
final Set<PsiMember> alreadyMarkedToBeChecked,
|
||||
@Nullable final PsiClass... classes) {
|
||||
if (classes != null && classes.length > 0) {
|
||||
final Set<String> groupDependencies = new LinkedHashSet<String>();
|
||||
TestNGUtil.collectAnnotationValues(groupDependencies, "dependsOnGroups", methods, classes);
|
||||
final Set<PsiMember> membersToCheckNow = new LinkedHashSet<PsiMember>();
|
||||
if (!groupDependencies.isEmpty()) {
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
public void run() {
|
||||
final Project project = classes[0].getProject();
|
||||
final PsiClass testAnnotation =
|
||||
JavaPsiFacade.getInstance(project).findClass(TestNGUtil.TEST_ANNOTATION_FQN, GlobalSearchScope.allScope(project));
|
||||
LOG.assertTrue(testAnnotation != null);
|
||||
for (PsiMember psiMember : AnnotatedMembersSearch.search(testAnnotation, getSearchScope())) {
|
||||
final PsiAnnotation annotation = AnnotationUtil.findAnnotation(psiMember, TestNGUtil.TEST_ANNOTATION_FQN);
|
||||
if (TestNGUtil.isAnnotatedWithParameter(annotation, "groups", groupDependencies)) {
|
||||
if (appendMember(psiMember, alreadyMarkedToBeChecked, results)) {
|
||||
membersToCheckNow.add(psiMember);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
collectDependsOnMethods(results, alreadyMarkedToBeChecked, membersToCheckNow, methods, classes);
|
||||
|
||||
if (methods == null) {
|
||||
for (PsiClass c : classes) {
|
||||
results.put(c, new LinkedHashMap<PsiMethod, List<String>>());
|
||||
}
|
||||
} else {
|
||||
for (PsiMember psiMember : membersToCheckNow) {
|
||||
PsiClass psiClass;
|
||||
PsiMethod[] meths = null;
|
||||
if (psiMember instanceof PsiMethod) {
|
||||
psiClass = psiMember.getContainingClass();
|
||||
meths = new PsiMethod[] {(PsiMethod)psiMember};
|
||||
} else {
|
||||
psiClass = (PsiClass)psiMember;
|
||||
}
|
||||
calculateDependencies(meths, results, alreadyMarkedToBeChecked, psiClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void collectDependsOnMethods(final Map<PsiClass, Map<PsiMethod, List<String>>> results,
|
||||
final Set<PsiMember> alreadyMarkedToBeChecked,
|
||||
final Set<PsiMember> membersToCheckNow,
|
||||
final PsiMethod[] methods,
|
||||
final PsiClass... classes) {
|
||||
final PsiClass[] psiClasses;
|
||||
if (methods != null && methods.length > 0) {
|
||||
final Set<PsiClass> containingClasses = new LinkedHashSet<PsiClass>();
|
||||
for (final PsiMethod method : methods) {
|
||||
containingClasses.add(ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
|
||||
@Override
|
||||
public PsiClass compute() {
|
||||
return method.getContainingClass();
|
||||
}
|
||||
}));
|
||||
}
|
||||
psiClasses = containingClasses.toArray(new PsiClass[containingClasses.size()]);
|
||||
} else {
|
||||
psiClasses = classes;
|
||||
}
|
||||
for (final PsiClass containingClass : psiClasses) {
|
||||
final Set<String> testMethodDependencies = new LinkedHashSet<String>();
|
||||
TestNGUtil.collectAnnotationValues(testMethodDependencies, "dependsOnMethods", methods, containingClass);
|
||||
if (!testMethodDependencies.isEmpty()) {
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
public void run() {
|
||||
final Project project = containingClass.getProject();
|
||||
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
|
||||
for (String dependency : testMethodDependencies) {
|
||||
final String className = StringUtil.getPackageName(dependency);
|
||||
final String methodName = StringUtil.getShortName(dependency);
|
||||
if (StringUtil.isEmpty(className)) {
|
||||
checkClassMethods(methodName, containingClass, alreadyMarkedToBeChecked, membersToCheckNow, results);
|
||||
}
|
||||
else {
|
||||
final PsiClass aClass = psiFacade.findClass(className, containingClass.getResolveScope());
|
||||
if (aClass != null) {
|
||||
checkClassMethods(methodName, aClass, alreadyMarkedToBeChecked, membersToCheckNow, results);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkClassMethods(String methodName,
|
||||
PsiClass containingClass,
|
||||
Set<PsiMember> alreadyMarkedToBeChecked,
|
||||
Set<PsiMember> membersToCheckNow,
|
||||
Map<PsiClass, Map<PsiMethod, List<String>>> results) {
|
||||
final PsiMethod[] psiMethods = containingClass.findMethodsByName(methodName, true);
|
||||
for (PsiMethod method : psiMethods) {
|
||||
if (AnnotationUtil.isAnnotated(method, TestNGUtil.TEST_ANNOTATION_FQN, false) &&
|
||||
appendMember(method, alreadyMarkedToBeChecked, results)) {
|
||||
membersToCheckNow.add(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean appendMember(final PsiMember psiMember,
|
||||
final Set<PsiMember> underConsideration,
|
||||
final Map<PsiClass, Map<PsiMethod, List<String>>> results) {
|
||||
boolean result = false;
|
||||
final PsiClass psiClass = psiMember instanceof PsiClass ? ((PsiClass)psiMember) : psiMember.getContainingClass();
|
||||
Map<PsiMethod, List<String>> psiMethods = results.get(psiClass);
|
||||
if (psiMethods == null) {
|
||||
psiMethods = new LinkedHashMap<PsiMethod, List<String>>();
|
||||
results.put(psiClass, psiMethods);
|
||||
if (psiMember instanceof PsiClass) {
|
||||
result = underConsideration.add(psiMember);
|
||||
}
|
||||
}
|
||||
if (psiMember instanceof PsiMethod) {
|
||||
final boolean add = psiMethods.put((PsiMethod)psiMember, Collections.<String>emptyList()) != null;
|
||||
if (add) {
|
||||
return underConsideration.add(psiMember);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private GlobalSearchScope getSearchScope() {
|
||||
final TestData data = myConfig.getPersistantData();
|
||||
final Module module = myConfig.getConfigurationModule().getModule();
|
||||
return data.TEST_OBJECT.equals(TestType.PACKAGE.getType())
|
||||
? myConfig.getPersistantData().getScope().getSourceScope(myConfig).getGlobalSearchScope()
|
||||
: module != null ? GlobalSearchScope.moduleWithDependenciesScope(module) : GlobalSearchScope.projectScope(myConfig.getProject());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
-64
@@ -29,7 +29,6 @@ import com.intellij.execution.configuration.EnvironmentVariablesComponent;
|
||||
import com.intellij.execution.configurations.*;
|
||||
import com.intellij.execution.junit.RefactoringListeners;
|
||||
import com.intellij.execution.runners.ExecutionEnvironment;
|
||||
import com.intellij.execution.testframework.SourceScope;
|
||||
import com.intellij.execution.testframework.TestSearchScope;
|
||||
import com.intellij.execution.util.JavaParametersUtil;
|
||||
import com.intellij.execution.util.ProgramParametersUtil;
|
||||
@@ -47,12 +46,12 @@ import com.intellij.refactoring.listeners.RefactoringElementAdapter;
|
||||
import com.intellij.refactoring.listeners.RefactoringElementListener;
|
||||
import com.intellij.refactoring.listeners.UndoRefactoringElementListener;
|
||||
import com.theoryinpractice.testng.model.TestData;
|
||||
import com.theoryinpractice.testng.model.TestNGTestObject;
|
||||
import com.theoryinpractice.testng.model.TestType;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.testng.xml.Parser;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -68,7 +67,7 @@ public class TestNGConfiguration extends ModuleBasedConfiguration<JavaRunConfigu
|
||||
public boolean ALTERNATIVE_JRE_PATH_ENABLED;
|
||||
public String ALTERNATIVE_JRE_PATH;
|
||||
|
||||
private static final Object PARSE_LOCK = new Object();
|
||||
|
||||
|
||||
public static final String DEFAULT_PACKAGE_NAME = ExecutionBundle.message("default.package.presentable.name");
|
||||
public static final String DEFAULT_PACKAGE_CONFIGURATION_NAME = ExecutionBundle.message("default.package.configuration.name");
|
||||
@@ -149,32 +148,14 @@ public class TestNGConfiguration extends ModuleBasedConfiguration<JavaRunConfigu
|
||||
|
||||
@Override
|
||||
public String suggestedName() {
|
||||
return data.getGeneratedName(getConfigurationModule());
|
||||
final TestNGTestObject testObject = TestNGTestObject.fromConfig(this);
|
||||
return testObject != null ? testObject.getGeneratedName() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActionName() {
|
||||
if (TestType.CLASS.getType().equals(data.TEST_OBJECT)) {
|
||||
String shortName = JavaExecutionUtil.getShortClassName(data.MAIN_CLASS_NAME);
|
||||
return ProgramRunnerUtil.shortenName(shortName, 0);
|
||||
}
|
||||
if (TestType.PACKAGE.getType().equals(data.TEST_OBJECT)) {
|
||||
String s = getName();
|
||||
if (!isGeneratedName()) return '\"' + s + '\"';
|
||||
if (data.getPackageName().trim().length() > 0) {
|
||||
return "Tests in \"" + data.getPackageName() + '\"';
|
||||
}
|
||||
else {
|
||||
return "All Tests";
|
||||
}
|
||||
}
|
||||
if (TestType.METHOD.getType().equals(data.TEST_OBJECT)) {
|
||||
return data.getMethodName() + "()";
|
||||
}
|
||||
if (TestType.SUITE.getType().equals(data.TEST_OBJECT)) {
|
||||
return data.getSuiteName();
|
||||
}
|
||||
return data.getGroupName();
|
||||
final TestNGTestObject testObject = TestNGTestObject.fromConfig(this);
|
||||
return testObject != null ? ProgramRunnerUtil.shortenName(testObject.getActionName(), 0) : null;
|
||||
}
|
||||
|
||||
public void setVMParameters(String value) {
|
||||
@@ -299,45 +280,9 @@ public class TestNGConfiguration extends ModuleBasedConfiguration<JavaRunConfigu
|
||||
|
||||
@Override
|
||||
public void checkConfiguration() throws RuntimeConfigurationException {
|
||||
if (data.TEST_OBJECT.equals(TestType.CLASS.getType()) || data.TEST_OBJECT.equals(TestType.METHOD.getType())) {
|
||||
final SourceScope scope = data.getScope().getSourceScope(this);
|
||||
if (scope == null) {
|
||||
throw new RuntimeConfigurationException("Invalid scope specified");
|
||||
}
|
||||
PsiClass psiClass = JavaPsiFacade.getInstance(project).findClass(data.getMainClassName(), scope.getGlobalSearchScope());
|
||||
if (psiClass == null) throw new RuntimeConfigurationException("Class '" + data.getMainClassName() + "' not found");
|
||||
if (data.TEST_OBJECT.equals(TestType.METHOD.getType())) {
|
||||
PsiMethod[] methods = psiClass.findMethodsByName(data.getMethodName(), true);
|
||||
if (methods.length == 0) {
|
||||
throw new RuntimeConfigurationException("Method '" + data.getMethodName() + "' not found");
|
||||
}
|
||||
for (PsiMethod method : methods) {
|
||||
if (!method.hasModifierProperty(PsiModifier.PUBLIC)) {
|
||||
throw new RuntimeConfigurationException("Non public method '" + data.getMethodName() + "'specified");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (data.TEST_OBJECT.equals(TestType.PACKAGE.getType())) {
|
||||
PsiPackage psiPackage = JavaPsiFacade.getInstance(project).findPackage(data.getPackageName());
|
||||
if (psiPackage == null) throw new RuntimeConfigurationException("Package '" + data.getPackageName() + "' not found");
|
||||
}
|
||||
else if (data.TEST_OBJECT.equals(TestType.SUITE.getType())) {
|
||||
try {
|
||||
final Parser parser = new Parser(data.getSuiteName());
|
||||
parser.setLoadClasses(false);
|
||||
synchronized (PARSE_LOCK) {
|
||||
parser.parse();//try to parse suite.xml
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeConfigurationException("Unable to parse '" + data.getSuiteName() + "' specified");
|
||||
}
|
||||
} else if (data.TEST_OBJECT.equals(TestType.PATTERN.getType())) {
|
||||
final Set<String> patterns = data.getPatterns();
|
||||
if (patterns.isEmpty()) {
|
||||
throw new RuntimeConfigurationWarning("No pattern selected");
|
||||
}
|
||||
final TestNGTestObject testObject = TestNGTestObject.fromConfig(this);
|
||||
if (testObject != null) {
|
||||
testObject.checkConfiguration();
|
||||
}
|
||||
JavaRunConfigurationExtensionManager.checkConfigurationIsValid(this);
|
||||
ProgramParametersUtil.checkWorkingDirectoryExist(this, getProject(), getConfigurationModule().getModule());
|
||||
|
||||
+2
-1
@@ -33,6 +33,7 @@ import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.theoryinpractice.testng.model.TestData;
|
||||
import com.theoryinpractice.testng.model.TestNGTestObject;
|
||||
import org.testng.IDEATestNGRemoteListener;
|
||||
|
||||
public abstract class TestNGConfigurationProducer extends JavaRunConfigurationProducerBase<TestNGConfiguration> implements Cloneable {
|
||||
@@ -58,7 +59,7 @@ public abstract class TestNGConfigurationProducer extends JavaRunConfigurationPr
|
||||
String paramSetName = contextLocation instanceof PsiMemberParameterizedLocation
|
||||
? getInvocationNumber(((PsiMemberParameterizedLocation)contextLocation).getParamSetName()) : null;
|
||||
if (paramSetName != null && !Comparing.strEqual(paramSetName, testNGConfiguration.getProgramParameters())) return false;
|
||||
TestData testobject = testNGConfiguration.getPersistantData();
|
||||
TestNGTestObject testobject = TestNGTestObject.fromConfig(testNGConfiguration);
|
||||
if (testobject != null) {
|
||||
if (testobject.isConfiguredByElement(element)) {
|
||||
final Module configurationModule = testNGConfiguration.getConfigurationModule().getModule();
|
||||
|
||||
+3
-1
@@ -33,6 +33,7 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.theoryinpractice.testng.model.TestData;
|
||||
import com.theoryinpractice.testng.model.TestNGTestObject;
|
||||
import icons.TestngIcons;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -72,7 +73,8 @@ public class TestNGConfigurationType implements ConfigurationType
|
||||
return false;
|
||||
else {
|
||||
final PsiElement element = location.getPsiElement();
|
||||
if (testobject.isConfiguredByElement(element)) {
|
||||
final TestNGTestObject testNGTestObject = TestNGTestObject.fromConfig(config);
|
||||
if (testNGTestObject != null && testNGTestObject.isConfiguredByElement(element)) {
|
||||
final Module configurationModule = config.getConfigurationModule().getModule();
|
||||
if (Comparing.equal(location.getModule(), configurationModule)) return true;
|
||||
|
||||
|
||||
+5
-7
@@ -18,9 +18,7 @@ package com.theoryinpractice.testng.configuration;
|
||||
|
||||
import com.intellij.execution.*;
|
||||
import com.intellij.execution.configurations.*;
|
||||
import com.intellij.execution.process.OSProcessHandler;
|
||||
import com.intellij.execution.process.ProcessAdapter;
|
||||
import com.intellij.execution.process.ProcessEvent;
|
||||
import com.intellij.execution.process.*;
|
||||
import com.intellij.execution.runners.ExecutionEnvironment;
|
||||
import com.intellij.execution.runners.ProgramRunner;
|
||||
import com.intellij.execution.testframework.*;
|
||||
@@ -76,10 +74,10 @@ public class TestNGRunnableState extends JavaTestFrameworkRunnableState<TestNGCo
|
||||
@NotNull
|
||||
@Override
|
||||
protected OSProcessHandler startProcess() throws ExecutionException {
|
||||
final OSProcessHandler handler = super.startProcess();
|
||||
createSearchingForTestsTask().attachTaskToProcess(handler);
|
||||
|
||||
return handler;
|
||||
final OSProcessHandler processHandler = new KillableColoredProcessHandler(createCommandLine());
|
||||
ProcessTerminatedListener.attach(processHandler);
|
||||
createSearchingForTestsTask().attachTaskToProcess(processHandler);
|
||||
return processHandler;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -18,16 +18,15 @@ package com.theoryinpractice.testng.model;
|
||||
import com.intellij.execution.ExternalizablePath;
|
||||
import com.intellij.execution.JavaExecutionUtil;
|
||||
import com.intellij.execution.Location;
|
||||
import com.intellij.execution.configurations.JavaRunConfigurationModule;
|
||||
import com.intellij.execution.junit.JUnitUtil;
|
||||
import com.intellij.execution.junit2.info.MethodLocation;
|
||||
import com.intellij.execution.testframework.TestSearchScope;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiPackage;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -174,26 +173,6 @@ public class TestData implements Cloneable
|
||||
return data;
|
||||
}
|
||||
|
||||
public String getGeneratedName(JavaRunConfigurationModule runconfigurationmodule) {
|
||||
if (TestType.PACKAGE.getType().equals(TEST_OBJECT)) if (getPackageName().length() == 0) return "<default>";
|
||||
else return getPackageName();
|
||||
String name = JavaExecutionUtil.getPresentableClassName(getMainClassName());
|
||||
if (TestType.METHOD.getType().equals(TEST_OBJECT)) {
|
||||
return name + '.' + getMethodName();
|
||||
}
|
||||
else if (TestType.SUITE.getType().equals(TEST_OBJECT)) {
|
||||
return getSuiteName();
|
||||
}
|
||||
else {
|
||||
if (TestType.PATTERN.getType().equals(TEST_OBJECT)) {
|
||||
final int size = myPatterns.size();
|
||||
if (size == 0) return "Temp suite";
|
||||
return StringUtil.getShortName(myPatterns.iterator().next()) + (size > 1 ? " and " + (size - 1) + " more" : "");
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public String getMainClassName() {
|
||||
return MAIN_CLASS_NAME == null ? "" : MAIN_CLASS_NAME;
|
||||
}
|
||||
@@ -217,28 +196,6 @@ public class TestData implements Cloneable
|
||||
return JavaExecutionUtil.findModule(psiclass);
|
||||
}
|
||||
|
||||
public boolean isConfiguredByElement(PsiElement element) {
|
||||
if (TEST_OBJECT.equals(TestType.PACKAGE.getType())) {
|
||||
if (element instanceof PsiPackage) {
|
||||
return Comparing.strEqual(PACKAGE_NAME, ((PsiPackage) element).getQualifiedName());
|
||||
} else if (element instanceof PsiDirectory) {
|
||||
final PsiPackage psiPackage = JavaDirectoryService.getInstance().getPackage(((PsiDirectory)element));
|
||||
return psiPackage != null && Comparing.strEqual(PACKAGE_NAME, psiPackage.getQualifiedName());
|
||||
}
|
||||
}
|
||||
|
||||
element = PsiTreeUtil.getParentOfType(element, PsiModifierListOwner.class, false);
|
||||
if (element instanceof PsiMethod && TEST_OBJECT.equals(TestType.METHOD.getType())) {
|
||||
final PsiClass aClass = ((PsiMethod) element).getContainingClass();
|
||||
return aClass != null &&
|
||||
Comparing.strEqual(MAIN_CLASS_NAME, JavaExecutionUtil.getRuntimeQualifiedName(aClass)) &&
|
||||
Comparing.strEqual(METHOD_NAME, ((PsiMethod) element).getName());
|
||||
} else if (element instanceof PsiClass && TEST_OBJECT.equals(TestType.CLASS.getType())) {
|
||||
return Comparing.strEqual(MAIN_CLASS_NAME, JavaExecutionUtil.getRuntimeQualifiedName((PsiClass) element));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Map<String, String> getEnvs() {
|
||||
return ENVS;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.theoryinpractice.testng.model;
|
||||
|
||||
import com.intellij.execution.CantRunException;
|
||||
import com.intellij.execution.JavaExecutionUtil;
|
||||
import com.intellij.execution.configurations.RuntimeConfigurationException;
|
||||
import com.intellij.execution.testframework.SourceScope;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.ClassUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class TestNGTestClass extends TestNGTestObject {
|
||||
public TestNGTestClass(TestNGConfiguration config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes)
|
||||
throws CantRunException {
|
||||
final TestData data = myConfig.getPersistantData();
|
||||
//it's a class
|
||||
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(
|
||||
new Computable<PsiClass>() {
|
||||
@Nullable
|
||||
public PsiClass compute() {
|
||||
return ClassUtil.findPsiClass(PsiManager.getInstance(myConfig.getProject()), data.getMainClassName().replace('/', '.'), null, true, getSearchScope());
|
||||
}
|
||||
}
|
||||
);
|
||||
if (psiClass == null) {
|
||||
throw new CantRunException("No tests found in the class \"" + data.getMainClassName() + '\"');
|
||||
}
|
||||
if (null == ApplicationManager.getApplication().runReadAction(new Computable<String>() {
|
||||
@Nullable
|
||||
public String compute() {
|
||||
return psiClass.getQualifiedName();
|
||||
}
|
||||
})) {
|
||||
throw new CantRunException("Cannot test anonymous or local class \"" + data.getMainClassName() + '\"');
|
||||
}
|
||||
calculateDependencies(null, classes, psiClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGeneratedName() {
|
||||
return JavaExecutionUtil.getPresentableClassName(myConfig.getPersistantData().getMainClassName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActionName() {
|
||||
return JavaExecutionUtil.getShortClassName(myConfig.getPersistantData().MAIN_CLASS_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkConfiguration() throws RuntimeConfigurationException {
|
||||
final TestData data = myConfig.getPersistantData();
|
||||
final SourceScope scope = data.getScope().getSourceScope(myConfig);
|
||||
if (scope == null) {
|
||||
throw new RuntimeConfigurationException("Invalid scope specified");
|
||||
}
|
||||
PsiClass psiClass = JavaPsiFacade.getInstance(myConfig.getProject()).findClass(data.getMainClassName(), scope.getGlobalSearchScope());
|
||||
if (psiClass == null) throw new RuntimeConfigurationException("Class '" + data.getMainClassName() + "' not found");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConfiguredByElement(PsiElement element) {
|
||||
element = PsiTreeUtil.getParentOfType(element, PsiModifierListOwner.class, false);
|
||||
if (element instanceof PsiClass) {
|
||||
return Comparing.strEqual(myConfig.getPersistantData().getMethodName(), JavaExecutionUtil.getRuntimeQualifiedName((PsiClass) element));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.theoryinpractice.testng.model;
|
||||
|
||||
import com.intellij.execution.CantRunException;
|
||||
import com.intellij.execution.configurations.RuntimeConfigurationException;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
|
||||
import com.theoryinpractice.testng.util.TestNGUtil;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class TestNGTestGroup extends TestNGTestObject {
|
||||
public TestNGTestGroup(TestNGConfiguration config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes)
|
||||
throws CantRunException {
|
||||
final TestData data = myConfig.getPersistantData();
|
||||
//for a group, we include all classes
|
||||
final TestClassFilter classFilter =
|
||||
new TestClassFilter(data.getScope().getSourceScope(myConfig).getGlobalSearchScope(), myConfig.getProject(), true, true);
|
||||
PsiClass[] testClasses = TestNGUtil.getAllTestClasses(classFilter, false);
|
||||
if (testClasses != null) {
|
||||
for (PsiClass c : testClasses) {
|
||||
classes.put(c, new LinkedHashMap<PsiMethod, List<String>>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGeneratedName() {
|
||||
return myConfig.getPersistantData().getGroupName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActionName() {
|
||||
return myConfig.getPersistantData().getGroupName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkConfiguration() throws RuntimeConfigurationException {
|
||||
//check group exist?
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.theoryinpractice.testng.model;
|
||||
|
||||
import com.intellij.execution.CantRunException;
|
||||
import com.intellij.execution.JavaExecutionUtil;
|
||||
import com.intellij.execution.configurations.RuntimeConfigurationException;
|
||||
import com.intellij.execution.testframework.SourceScope;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.ClassUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class TestNGTestMethod extends TestNGTestObject {
|
||||
public TestNGTestMethod(TestNGConfiguration config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes)
|
||||
throws CantRunException {
|
||||
final TestData data = myConfig.getPersistantData();
|
||||
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(
|
||||
new Computable<PsiClass>() {
|
||||
@Nullable
|
||||
public PsiClass compute() {
|
||||
return ClassUtil.findPsiClass(PsiManager.getInstance(myConfig.getProject()), data.getMainClassName().replace('/', '.'), null, true, getSearchScope());
|
||||
}
|
||||
}
|
||||
);
|
||||
if (psiClass == null) {
|
||||
throw new CantRunException("No tests found in the class \"" + data.getMainClassName() + '\"');
|
||||
}
|
||||
if (null == ApplicationManager.getApplication().runReadAction(
|
||||
new Computable<String>() {
|
||||
@Nullable
|
||||
public String compute() {
|
||||
return psiClass.getQualifiedName();
|
||||
}
|
||||
}
|
||||
)) {
|
||||
throw new CantRunException("Cannot test anonymous or local class \"" + data.getMainClassName() + '\"');
|
||||
}
|
||||
collectTestMethods(classes, psiClass, data.getMethodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGeneratedName() {
|
||||
final TestData data = myConfig.getPersistantData();
|
||||
return JavaExecutionUtil.getPresentableClassName(data.getMainClassName()) + '.' + data.getMethodName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActionName() {
|
||||
return myConfig.getPersistantData().getMethodName() + "()";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkConfiguration() throws RuntimeConfigurationException {
|
||||
final TestData data = myConfig.getPersistantData();
|
||||
final SourceScope scope = data.getScope().getSourceScope(myConfig);
|
||||
if (scope == null) {
|
||||
throw new RuntimeConfigurationException("Invalid scope specified");
|
||||
}
|
||||
PsiClass psiClass = JavaPsiFacade.getInstance(myConfig.getProject()).findClass(data.getMainClassName(), scope.getGlobalSearchScope());
|
||||
if (psiClass == null) throw new RuntimeConfigurationException("Class '" + data.getMainClassName() + "' not found");
|
||||
PsiMethod[] methods = psiClass.findMethodsByName(data.getMethodName(), true);
|
||||
if (methods.length == 0) {
|
||||
throw new RuntimeConfigurationException("Method '" + data.getMethodName() + "' not found");
|
||||
}
|
||||
for (PsiMethod method : methods) {
|
||||
if (!method.hasModifierProperty(PsiModifier.PUBLIC)) {
|
||||
throw new RuntimeConfigurationException("Non public method '" + data.getMethodName() + "'specified");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConfiguredByElement(PsiElement element) {
|
||||
element = PsiTreeUtil.getParentOfType(element, PsiModifierListOwner.class, false);
|
||||
if (element instanceof PsiMethod) {
|
||||
final PsiClass aClass = ((PsiMethod) element).getContainingClass();
|
||||
final TestData data = myConfig.getPersistantData();
|
||||
return aClass != null &&
|
||||
Comparing.strEqual(data.MAIN_CLASS_NAME, JavaExecutionUtil.getRuntimeQualifiedName(aClass)) &&
|
||||
Comparing.strEqual(data.METHOD_NAME, ((PsiMethod) element).getName());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.theoryinpractice.testng.model;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.execution.CantRunException;
|
||||
import com.intellij.execution.configurations.RuntimeConfigurationException;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.searches.AnnotatedMembersSearch;
|
||||
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
|
||||
import com.theoryinpractice.testng.util.TestNGUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public abstract class TestNGTestObject {
|
||||
private static final Logger LOG = Logger.getInstance("#" + TestNGTestObject.class.getName());
|
||||
protected final TestNGConfiguration myConfig;
|
||||
|
||||
public TestNGTestObject(TestNGConfiguration config) {
|
||||
myConfig = config;
|
||||
}
|
||||
|
||||
public static TestNGTestObject fromConfig(TestNGConfiguration config) {
|
||||
final TestData data = config.getPersistantData();
|
||||
if (data.TEST_OBJECT.equals(TestType.PACKAGE.getType())) {
|
||||
return new TestNGTestPackage(config);
|
||||
}
|
||||
if (data.TEST_OBJECT.equals(TestType.CLASS.getType())) {
|
||||
return new TestNGTestClass(config);
|
||||
}
|
||||
if (data.TEST_OBJECT.equals(TestType.METHOD.getType())) {
|
||||
return new TestNGTestMethod(config);
|
||||
}
|
||||
|
||||
if (data.TEST_OBJECT.equals(TestType.GROUP.getType())) {
|
||||
return new TestNGTestGroup(config);
|
||||
}
|
||||
|
||||
if (data.TEST_OBJECT.equals(TestType.PATTERN.getType())) {
|
||||
return new TestNGTestPattern(config);
|
||||
}
|
||||
|
||||
if (data.TEST_OBJECT.equals(TestType.SUITE.getType())){
|
||||
return new TestNGTestSuite(config);
|
||||
}
|
||||
assert false : data.TEST_OBJECT;
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract void fillTestObjects(final Map<PsiClass, Map<PsiMethod, List<String>>> classes) throws CantRunException;
|
||||
public abstract String getGeneratedName();
|
||||
public abstract String getActionName();
|
||||
public abstract void checkConfiguration() throws RuntimeConfigurationException;
|
||||
|
||||
public boolean isConfiguredByElement(PsiElement element) {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void calculateDependencies(PsiMethod[] methods,
|
||||
final Map<PsiClass, Map<PsiMethod, List<String>>> results,
|
||||
@Nullable final PsiClass... classes) {
|
||||
calculateDependencies(methods, results, new LinkedHashSet<PsiMember>(), classes);
|
||||
}
|
||||
|
||||
private void calculateDependencies(final PsiMethod[] methods,
|
||||
final Map<PsiClass, Map<PsiMethod, List<String>>> results,
|
||||
final Set<PsiMember> alreadyMarkedToBeChecked,
|
||||
@Nullable final PsiClass... classes) {
|
||||
if (classes != null && classes.length > 0) {
|
||||
final Set<String> groupDependencies = new LinkedHashSet<String>();
|
||||
TestNGUtil.collectAnnotationValues(groupDependencies, "dependsOnGroups", methods, classes);
|
||||
final Set<PsiMember> membersToCheckNow = new LinkedHashSet<PsiMember>();
|
||||
if (!groupDependencies.isEmpty()) {
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
public void run() {
|
||||
final Project project = classes[0].getProject();
|
||||
final PsiClass testAnnotation =
|
||||
JavaPsiFacade.getInstance(project).findClass(TestNGUtil.TEST_ANNOTATION_FQN, GlobalSearchScope.allScope(project));
|
||||
LOG.assertTrue(testAnnotation != null);
|
||||
for (PsiMember psiMember : AnnotatedMembersSearch.search(testAnnotation, getSearchScope())) {
|
||||
final PsiAnnotation annotation = AnnotationUtil.findAnnotation(psiMember, TestNGUtil.TEST_ANNOTATION_FQN);
|
||||
if (TestNGUtil.isAnnotatedWithParameter(annotation, "groups", groupDependencies)) {
|
||||
if (appendMember(psiMember, alreadyMarkedToBeChecked, results)) {
|
||||
membersToCheckNow.add(psiMember);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
collectDependsOnMethods(results, alreadyMarkedToBeChecked, membersToCheckNow, methods, classes);
|
||||
|
||||
if (methods == null) {
|
||||
for (PsiClass c : classes) {
|
||||
results.put(c, new LinkedHashMap<PsiMethod, List<String>>());
|
||||
}
|
||||
} else {
|
||||
for (PsiMember psiMember : membersToCheckNow) {
|
||||
PsiClass psiClass;
|
||||
PsiMethod[] meths = null;
|
||||
if (psiMember instanceof PsiMethod) {
|
||||
psiClass = psiMember.getContainingClass();
|
||||
meths = new PsiMethod[] {(PsiMethod)psiMember};
|
||||
} else {
|
||||
psiClass = (PsiClass)psiMember;
|
||||
}
|
||||
calculateDependencies(meths, results, alreadyMarkedToBeChecked, psiClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void collectDependsOnMethods(final Map<PsiClass, Map<PsiMethod, List<String>>> results,
|
||||
final Set<PsiMember> alreadyMarkedToBeChecked,
|
||||
final Set<PsiMember> membersToCheckNow,
|
||||
final PsiMethod[] methods,
|
||||
final PsiClass... classes) {
|
||||
final PsiClass[] psiClasses;
|
||||
if (methods != null && methods.length > 0) {
|
||||
final Set<PsiClass> containingClasses = new LinkedHashSet<PsiClass>();
|
||||
for (final PsiMethod method : methods) {
|
||||
containingClasses.add(ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
|
||||
@Override
|
||||
public PsiClass compute() {
|
||||
return method.getContainingClass();
|
||||
}
|
||||
}));
|
||||
}
|
||||
psiClasses = containingClasses.toArray(new PsiClass[containingClasses.size()]);
|
||||
} else {
|
||||
psiClasses = classes;
|
||||
}
|
||||
for (final PsiClass containingClass : psiClasses) {
|
||||
final Set<String> testMethodDependencies = new LinkedHashSet<String>();
|
||||
TestNGUtil.collectAnnotationValues(testMethodDependencies, "dependsOnMethods", methods, containingClass);
|
||||
if (!testMethodDependencies.isEmpty()) {
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
public void run() {
|
||||
final Project project = containingClass.getProject();
|
||||
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
|
||||
for (String dependency : testMethodDependencies) {
|
||||
final String className = StringUtil.getPackageName(dependency);
|
||||
final String methodName = StringUtil.getShortName(dependency);
|
||||
if (StringUtil.isEmpty(className)) {
|
||||
checkClassMethods(methodName, containingClass, alreadyMarkedToBeChecked, membersToCheckNow, results);
|
||||
}
|
||||
else {
|
||||
final PsiClass aClass = psiFacade.findClass(className, containingClass.getResolveScope());
|
||||
if (aClass != null) {
|
||||
checkClassMethods(methodName, aClass, alreadyMarkedToBeChecked, membersToCheckNow, results);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkClassMethods(String methodName,
|
||||
PsiClass containingClass,
|
||||
Set<PsiMember> alreadyMarkedToBeChecked,
|
||||
Set<PsiMember> membersToCheckNow,
|
||||
Map<PsiClass, Map<PsiMethod, List<String>>> results) {
|
||||
final PsiMethod[] psiMethods = containingClass.findMethodsByName(methodName, true);
|
||||
for (PsiMethod method : psiMethods) {
|
||||
if (AnnotationUtil.isAnnotated(method, TestNGUtil.TEST_ANNOTATION_FQN, false) &&
|
||||
appendMember(method, alreadyMarkedToBeChecked, results)) {
|
||||
membersToCheckNow.add(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean appendMember(final PsiMember psiMember,
|
||||
final Set<PsiMember> underConsideration,
|
||||
final Map<PsiClass, Map<PsiMethod, List<String>>> results) {
|
||||
boolean result = false;
|
||||
final PsiClass psiClass = psiMember instanceof PsiClass ? ((PsiClass)psiMember) : psiMember.getContainingClass();
|
||||
Map<PsiMethod, List<String>> psiMethods = results.get(psiClass);
|
||||
if (psiMethods == null) {
|
||||
psiMethods = new LinkedHashMap<PsiMethod, List<String>>();
|
||||
results.put(psiClass, psiMethods);
|
||||
if (psiMember instanceof PsiClass) {
|
||||
result = underConsideration.add(psiMember);
|
||||
}
|
||||
}
|
||||
if (psiMember instanceof PsiMethod) {
|
||||
final boolean add = psiMethods.put((PsiMethod)psiMember, Collections.<String>emptyList()) != null;
|
||||
if (add) {
|
||||
return underConsideration.add(psiMember);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected GlobalSearchScope getSearchScope() {
|
||||
final TestData data = myConfig.getPersistantData();
|
||||
final Module module = myConfig.getConfigurationModule().getModule();
|
||||
return data.TEST_OBJECT.equals(TestType.PACKAGE.getType())
|
||||
? myConfig.getPersistantData().getScope().getSourceScope(myConfig).getGlobalSearchScope()
|
||||
: module != null ? GlobalSearchScope.moduleWithDependenciesScope(module) : GlobalSearchScope.projectScope(myConfig.getProject());
|
||||
}
|
||||
|
||||
protected void collectTestMethods(Map<PsiClass, Map<PsiMethod, List<String>>> classes, final PsiClass psiClass, final String methodName) {
|
||||
final PsiMethod[] methods = ApplicationManager.getApplication().runReadAction(
|
||||
new Computable<PsiMethod[]>() {
|
||||
public PsiMethod[] compute() {
|
||||
return psiClass.findMethodsByName(methodName, true);
|
||||
}
|
||||
}
|
||||
);
|
||||
calculateDependencies(methods, classes, psiClass);
|
||||
Map<PsiMethod, List<String>> psiMethods = classes.get(psiClass);
|
||||
if (psiMethods == null) {
|
||||
psiMethods = new LinkedHashMap<PsiMethod, List<String>>();
|
||||
classes.put(psiClass, psiMethods);
|
||||
}
|
||||
for (PsiMethod method : methods) {
|
||||
psiMethods.put(method, Collections.<String>emptyList());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.theoryinpractice.testng.model;
|
||||
|
||||
import com.intellij.execution.CantRunException;
|
||||
import com.intellij.execution.JavaExecutionUtil;
|
||||
import com.intellij.execution.configurations.RuntimeConfigurationException;
|
||||
import com.intellij.execution.testframework.TestSearchScope;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.PackageScope;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
|
||||
import com.theoryinpractice.testng.util.TestNGUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class TestNGTestPackage extends TestNGTestObject {
|
||||
public TestNGTestPackage(TestNGConfiguration configuration) {
|
||||
super(configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes) throws CantRunException {
|
||||
final String packageName = myConfig.getPersistantData().getPackageName();
|
||||
PsiPackage psiPackage = ApplicationManager.getApplication().runReadAction(
|
||||
new Computable<PsiPackage>() {
|
||||
@Nullable
|
||||
public PsiPackage compute() {
|
||||
return JavaPsiFacade.getInstance(myConfig.getProject()).findPackage(packageName);
|
||||
}
|
||||
}
|
||||
);
|
||||
if (psiPackage == null) {
|
||||
throw CantRunException.packageNotFound(packageName);
|
||||
}
|
||||
else {
|
||||
TestSearchScope scope = myConfig.getPersistantData().getScope();
|
||||
//TODO we should narrow this down by module really, if that's what's specified
|
||||
TestClassFilter projectFilter =
|
||||
new TestClassFilter(scope.getSourceScope(myConfig).getGlobalSearchScope(), myConfig.getProject(), true, true);
|
||||
TestClassFilter filter = projectFilter.intersectionWith(PackageScope.packageScope(psiPackage, true));
|
||||
calculateDependencies(null, classes, TestNGUtil.getAllTestClasses(filter, false));
|
||||
if (classes.size() == 0) {
|
||||
throw new CantRunException("No tests found in the package \"" + packageName + '\"');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGeneratedName() {
|
||||
final String packageName = myConfig.getPersistantData().getPackageName();
|
||||
return packageName.length() == 0 ? "<default>" : packageName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActionName() {
|
||||
String s = myConfig.getName();
|
||||
if (!myConfig.isGeneratedName()) return '\"' + s + '\"';
|
||||
if (myConfig.getPersistantData().getPackageName().trim().length() > 0) {
|
||||
return "Tests in \"" + myConfig.getPersistantData().getPackageName() + '\"';
|
||||
}
|
||||
else {
|
||||
return "All Tests";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkConfiguration() throws RuntimeConfigurationException {
|
||||
final TestData data = myConfig.getPersistantData();
|
||||
PsiPackage psiPackage = JavaPsiFacade.getInstance(myConfig.getProject()).findPackage(data.getPackageName());
|
||||
if (psiPackage == null) throw new RuntimeConfigurationException("Package '" + data.getPackageName() + "' not found");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConfiguredByElement(PsiElement element) {
|
||||
final String packageName = myConfig.getPersistantData().getPackageName();
|
||||
if (element instanceof PsiPackage) {
|
||||
return Comparing.strEqual(packageName, ((PsiPackage)element).getQualifiedName());
|
||||
} else if (element instanceof PsiDirectory) {
|
||||
final PsiPackage psiPackage = JavaDirectoryService.getInstance().getPackage(((PsiDirectory)element));
|
||||
return psiPackage != null && Comparing.strEqual(packageName, psiPackage.getQualifiedName());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.theoryinpractice.testng.model;
|
||||
|
||||
import com.intellij.execution.CantRunException;
|
||||
import com.intellij.execution.configurations.RuntimeConfigurationException;
|
||||
import com.intellij.execution.configurations.RuntimeConfigurationWarning;
|
||||
import com.intellij.execution.testframework.TestSearchScope;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.util.ClassUtil;
|
||||
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
|
||||
import com.theoryinpractice.testng.util.TestNGUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
public class TestNGTestPattern extends TestNGTestObject {
|
||||
private static final Logger LOG = Logger.getInstance("#" + TestNGTestPattern.class.getName());
|
||||
|
||||
public TestNGTestPattern(TestNGConfiguration config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes)
|
||||
throws CantRunException {
|
||||
final TestData data = myConfig.getPersistantData();
|
||||
for (final String pattern : data.getPatterns()) {
|
||||
final String className;
|
||||
final String methodName;
|
||||
if (pattern.contains(",")) {
|
||||
methodName = StringUtil.getShortName(pattern, ',');
|
||||
className = StringUtil.getPackageName(pattern, ',');
|
||||
} else {
|
||||
className = pattern;
|
||||
methodName = null;
|
||||
}
|
||||
|
||||
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiClass compute() {
|
||||
return ClassUtil.findPsiClass(PsiManager.getInstance(myConfig.getProject()), className.replace('/', '.'), null, true, getSearchScope());
|
||||
}
|
||||
});
|
||||
if (psiClass != null) {
|
||||
final Boolean hasTest = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
|
||||
@Override
|
||||
public Boolean compute() {
|
||||
return TestNGUtil.hasTest(psiClass);
|
||||
}
|
||||
});
|
||||
if (hasTest) {
|
||||
if (StringUtil.isEmpty(methodName)) {
|
||||
calculateDependencies(null, classes, psiClass);
|
||||
}
|
||||
else {
|
||||
collectTestMethods(classes, psiClass, methodName);
|
||||
}
|
||||
} else {
|
||||
throw new CantRunException("No tests found in class " + className);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (classes.size() != data.getPatterns().size()) {
|
||||
TestSearchScope scope = myConfig.getPersistantData().getScope();
|
||||
final List<Pattern> compilePatterns = new ArrayList<Pattern>();
|
||||
for (String p : data.getPatterns()) {
|
||||
final Pattern compilePattern;
|
||||
try {
|
||||
compilePattern = Pattern.compile(p);
|
||||
}
|
||||
catch (PatternSyntaxException e) {
|
||||
continue;
|
||||
}
|
||||
if (compilePattern != null) {
|
||||
compilePatterns.add(compilePattern);
|
||||
}
|
||||
}
|
||||
TestClassFilter projectFilter =
|
||||
new TestClassFilter(scope.getSourceScope(myConfig).getGlobalSearchScope(), myConfig.getProject(), true, true){
|
||||
@Override
|
||||
public boolean isAccepted(PsiClass psiClass) {
|
||||
if (super.isAccepted(psiClass)) {
|
||||
final String qualifiedName = psiClass.getQualifiedName();
|
||||
LOG.assertTrue(qualifiedName != null);
|
||||
for (Pattern pattern : compilePatterns) {
|
||||
if (pattern.matcher(qualifiedName).matches()) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
calculateDependencies(null, classes, TestNGUtil.getAllTestClasses(projectFilter, false));
|
||||
if (classes.size() == 0) {
|
||||
throw new CantRunException("No tests found in for patterns \"" + StringUtil.join(data.getPatterns(), " || ") + '\"');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGeneratedName() {
|
||||
final Set<String> patterns = myConfig.getPersistantData().getPatterns();
|
||||
final int size = patterns.size();
|
||||
if (size == 0) return "Temp suite";
|
||||
return StringUtil.getShortName(patterns.iterator().next()) + (size > 1 ? " and " + (size - 1) + " more" : "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActionName() {
|
||||
return getGeneratedName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkConfiguration() throws RuntimeConfigurationException {
|
||||
final Set<String> patterns = myConfig.getPersistantData().getPatterns();
|
||||
if (patterns.isEmpty()) {
|
||||
throw new RuntimeConfigurationWarning("No pattern selected");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.theoryinpractice.testng.model;
|
||||
|
||||
import com.intellij.execution.CantRunException;
|
||||
import com.intellij.execution.configurations.RuntimeConfigurationException;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
|
||||
import org.testng.xml.Parser;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class TestNGTestSuite extends TestNGTestObject {
|
||||
private static final Object PARSE_LOCK = new Object();
|
||||
public TestNGTestSuite(TestNGConfiguration config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes) throws CantRunException {}
|
||||
|
||||
@Override
|
||||
public String getGeneratedName() {
|
||||
return myConfig.getPersistantData().getSuiteName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActionName() {
|
||||
return myConfig.getPersistantData().getSuiteName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkConfiguration() throws RuntimeConfigurationException {
|
||||
final TestData data = myConfig.getPersistantData();
|
||||
try {
|
||||
final Parser parser = new Parser(data.getSuiteName());
|
||||
parser.setLoadClasses(false);
|
||||
synchronized (PARSE_LOCK) {
|
||||
parser.parse();//try to parse suite.xml
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeConfigurationException("Unable to parse '" + data.getSuiteName() + "' specified");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -436,7 +436,7 @@ public class TestNGUtil {
|
||||
public void run() {
|
||||
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
|
||||
|
||||
final Collection<PsiClass> set = new HashSet<PsiClass>();
|
||||
final Collection<PsiClass> set = new LinkedHashSet<PsiClass>();
|
||||
PsiManager manager = PsiManager.getInstance(filter.getProject());
|
||||
GlobalSearchScope scope = filter.getScope();
|
||||
GlobalSearchScope projectScope = GlobalSearchScope.projectScope(manager.getProject());
|
||||
@@ -445,7 +445,9 @@ public class TestNGUtil {
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
public void run() {
|
||||
if (filter.isAccepted(psiClass)) {
|
||||
indicator.setText2("Found test class " + psiClass.getQualifiedName());
|
||||
if (indicator != null) {
|
||||
indicator.setText2("Found test class " + psiClass.getQualifiedName());
|
||||
}
|
||||
set.add(psiClass);
|
||||
}
|
||||
}
|
||||
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.theoryinpractice.testng.configuration;
|
||||
|
||||
import com.intellij.execution.CantRunException;
|
||||
import com.intellij.execution.testframework.TestSearchScope;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
|
||||
import com.theoryinpractice.testng.model.TestData;
|
||||
import com.theoryinpractice.testng.model.TestNGTestObject;
|
||||
import com.theoryinpractice.testng.model.TestType;
|
||||
import org.testng.annotations.AfterMethod;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class DetectClassesToRunTest extends LightCodeInsightFixtureTestCase {
|
||||
@BeforeMethod
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
myFixture.addClass("package org.testng.annotations; @interface Test {public String[] dependsOnMethods() default {};}");
|
||||
myFixture.addClass("package org.testng.annotations; @interface BeforeClass {}");
|
||||
}
|
||||
|
||||
@AfterMethod
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonRelatedBeforeClassIncluded() throws Exception {
|
||||
final PsiClass configClass = myFixture.addClass("package p; public class AConfig {@org.testng.annotations.BeforeClass public void setup(){}}");
|
||||
final PsiClass testClass = myFixture.addClass("package p; public class ATest {@org.testng.annotations.Test public void testOne(){}}");
|
||||
//should not be included in resulted xml
|
||||
myFixture.addClass("package p; public class BTest {}");
|
||||
|
||||
doTestPackageConfiguration(configClass, testClass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonRelatedIncludedWhenConfigIsLocatedInSuperclassInAnotherPackage() throws Exception {
|
||||
myFixture.addClass("package a; public class AConfig {@org.testng.annotations.BeforeClass public void setup(){}}");
|
||||
final PsiClass emptyClassWithSuperConfig = myFixture.addClass("package p; import a.AConfig; public class BConfig extends AConfig {}");
|
||||
final PsiClass testClass = myFixture.addClass("package p; public class ATest {@org.testng.annotations.Test public void testOne(){}}");
|
||||
doTestPackageConfiguration(emptyClassWithSuperConfig, testClass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeforeClassIsIncludedIfRunOnlyOneMethod() throws Exception {
|
||||
final PsiClass aClass =
|
||||
myFixture.addClass("package a; public class AConfig {" +
|
||||
"@org.testng.annotations.BeforeClass public void setup(){}\n" +
|
||||
"@org.testng.annotations.Test public void testOne(){}\n" +
|
||||
"}");
|
||||
doTestMethodConfiguration(aClass, aClass.getMethods()[1]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneMethodWhenAnnotationIsOnBaseClassOnly() throws Exception {
|
||||
myFixture.addClass("package a; @org.testng.annotations.Test public class BaseClass {}");
|
||||
final PsiClass aClass =
|
||||
myFixture.addClass("package a; public class ATest extends BaseClass {" +
|
||||
" public void testOne(){}\n" +
|
||||
"}");
|
||||
doTestMethodConfiguration(aClass, aClass.getMethods());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneMethodWithDependencies() throws Exception {
|
||||
final PsiClass aClass =
|
||||
myFixture.addClass("package a; public class ATest {" +
|
||||
" @org.testng.annotations.Test\n" +
|
||||
" public void testTwo(){}\n " +
|
||||
" @org.testng.annotations.Test(dependsOnMethods=\"testTwo\")\n" +
|
||||
" public void testOne(){}\n" +
|
||||
"}");
|
||||
doTestMethodConfiguration(aClass, aClass.getMethods());
|
||||
}
|
||||
|
||||
private void doTestMethodConfiguration(PsiClass aClass, PsiMethod... expectedMethods) throws CantRunException {
|
||||
final TestNGConfiguration configuration =
|
||||
new TestNGConfiguration("testOne", getProject(), TestNGConfigurationType.getInstance().getConfigurationFactories()[0]);
|
||||
final TestData data = configuration.getPersistantData();
|
||||
data.TEST_OBJECT = TestType.METHOD.getType();
|
||||
data.METHOD_NAME = "testOne";
|
||||
data.setScope(TestSearchScope.SINGLE_MODULE);
|
||||
configuration.setModule(data.setMainClass(aClass));
|
||||
|
||||
final TestNGTestObject testObject = TestNGTestObject.fromConfig(configuration);
|
||||
assertNotNull(testObject);
|
||||
final LinkedHashMap<PsiClass, Map<PsiMethod, List<String>>> classes = new LinkedHashMap<PsiClass, Map<PsiMethod, List<String>>>();
|
||||
testObject.fillTestObjects(classes);
|
||||
assertContainsElements(classes.keySet(), aClass);
|
||||
final Map<PsiMethod, List<String>> methods = classes.get(aClass);
|
||||
assertContainsElements(methods.keySet(), expectedMethods);
|
||||
}
|
||||
|
||||
private void doTestPackageConfiguration(PsiClass... containingClasses) throws CantRunException {
|
||||
final TestNGConfiguration configuration =
|
||||
new TestNGConfiguration("p", getProject(), TestNGConfigurationType.getInstance().getConfigurationFactories()[0]);
|
||||
final TestData data = configuration.getPersistantData();
|
||||
data.TEST_OBJECT = TestType.PACKAGE.getType();
|
||||
data.PACKAGE_NAME = "p";
|
||||
data.setScope(TestSearchScope.WHOLE_PROJECT);
|
||||
|
||||
final TestNGTestObject testObject = TestNGTestObject.fromConfig(configuration);
|
||||
assertNotNull(testObject);
|
||||
final LinkedHashMap<PsiClass, Map<PsiMethod, List<String>>> classes = new LinkedHashMap<PsiClass, Map<PsiMethod, List<String>>>();
|
||||
testObject.fillTestObjects(classes);
|
||||
assertContainsElements(classes.keySet(), containingClasses);
|
||||
|
||||
for (PsiClass psiClass : containingClasses) {
|
||||
assertEmpty(classes.get(psiClass).keySet());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,4 +68,9 @@ public final class HistoryElement implements Copyable<HistoryElement> {
|
||||
public HistoryElement changeExpression(String expression) {
|
||||
return new HistoryElement(expression, variables, namespaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-3
@@ -20,6 +20,7 @@ import com.intellij.find.FindProgressIndicator;
|
||||
import com.intellij.find.FindSettings;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.actionSystem.LangDataKeys;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
@@ -34,6 +35,7 @@ import org.intellij.plugins.xpathView.XPathEvalAction;
|
||||
import org.intellij.plugins.xpathView.XPathProjectComponent;
|
||||
import org.intellij.plugins.xpathView.support.XPathSupport;
|
||||
import org.intellij.plugins.xpathView.ui.InputExpressionDialog;
|
||||
import org.intellij.plugins.xpathView.util.Namespace;
|
||||
import org.jaxen.JaxenException;
|
||||
import org.jaxen.XPathSyntaxException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -43,12 +45,12 @@ import java.util.Collections;
|
||||
public class FindByXPathAction extends AnAction {
|
||||
|
||||
public void update(AnActionEvent e) {
|
||||
final Project project = LangDataKeys.PROJECT.getData(e.getDataContext());
|
||||
final Project project = CommonDataKeys.PROJECT.getData(e.getDataContext());
|
||||
e.getPresentation().setEnabled(project != null);
|
||||
}
|
||||
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
final Project project = LangDataKeys.PROJECT.getData(e.getDataContext());
|
||||
final Project project = CommonDataKeys.PROJECT.getData(e.getDataContext());
|
||||
final Module module = LangDataKeys.MODULE.getData(e.getDataContext());
|
||||
|
||||
if (project != null) {
|
||||
@@ -141,7 +143,7 @@ public class FindByXPathAction extends AnAction {
|
||||
private static boolean validateExpression(Project project, String expression) {
|
||||
try {
|
||||
//noinspection unchecked
|
||||
XPathSupport.getInstance().createXPath(null, expression, Collections.<org.intellij.plugins.xpathView.util.Namespace>emptyList());
|
||||
XPathSupport.getInstance().createXPath(null, expression, Collections.<Namespace>emptyList());
|
||||
return true;
|
||||
} catch (XPathSyntaxException e) {
|
||||
Messages.showErrorDialog(project, e.getMultilineMessage(), "XPath Syntax Error");
|
||||
|
||||
+10
-46
@@ -23,13 +23,12 @@ import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.event.DocumentAdapter;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.ComboBox;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.xml.XmlElement;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.ui.EditorTextField;
|
||||
import com.intellij.ui.EditorComboBox;
|
||||
import com.intellij.ui.ListCellRendererWrapper;
|
||||
import com.intellij.uiDesigner.core.GridConstraints;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
@@ -54,14 +53,12 @@ import org.jetbrains.annotations.Nullable;
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ListDataEvent;
|
||||
import javax.swing.event.ListDataListener;
|
||||
import javax.swing.plaf.basic.BasicComboBoxEditor;
|
||||
import javax.xml.namespace.QName;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public abstract class InputExpressionDialog<FormType extends InputForm> extends ModeSwitchableDialog {
|
||||
protected final Project myProject;
|
||||
protected final FormType myForm;
|
||||
@@ -72,8 +69,7 @@ public abstract class InputExpressionDialog<FormType extends InputForm> extends
|
||||
private final Document myDocument;
|
||||
private final MultilineEditor myEditor;
|
||||
|
||||
private final EditorTextField myComboboxEditor;
|
||||
private final ComboBox myComboBox = new ComboBox(300);
|
||||
private final EditorComboBox myComboBox;
|
||||
private JComponent myEditorComponent;
|
||||
|
||||
@Nullable private Set<Namespace> myNamespaceCache;
|
||||
@@ -97,7 +93,6 @@ public abstract class InputExpressionDialog<FormType extends InputForm> extends
|
||||
myModel = new HistoryModel(_history, myDocument);
|
||||
myEditor = new MultilineEditor(myDocument, project, XPathFileType.XPATH, myModel);
|
||||
myModel.addListDataListener(new ListDataListener() {
|
||||
final PsiDocumentManager docMgr = PsiDocumentManager.getInstance(project);
|
||||
final DaemonCodeAnalyzer analyzer = DaemonCodeAnalyzer.getInstance(project);
|
||||
|
||||
public void intervalAdded(ListDataEvent e) {
|
||||
@@ -116,17 +111,15 @@ public abstract class InputExpressionDialog<FormType extends InputForm> extends
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
myComboboxEditor = new EditorTextField(myDocument, project, XPathFileType.XPATH);
|
||||
myComboBox = new EditorComboBox(myDocument, project, XPathFileType.XPATH);
|
||||
myComboBox.setRenderer(new ListCellRendererWrapper<HistoryElement>() {
|
||||
@Override
|
||||
public void customize(JList list, HistoryElement value, int index, boolean selected, boolean hasFocus) {
|
||||
setText(value != null ? value.expression : "");
|
||||
}
|
||||
@Override
|
||||
public void customize(JList list, HistoryElement value, int index, boolean selected, boolean hasFocus) {
|
||||
setText(value != null ? value.expression : "");
|
||||
}
|
||||
});
|
||||
myComboBox.setModel(myModel);
|
||||
|
||||
myComboBox.setEditor(new EditorAdapter(myComboboxEditor));
|
||||
myComboBox.setEditable(true);
|
||||
|
||||
myDocument.addDocumentListener(new DocumentAdapter() {
|
||||
@@ -254,7 +247,7 @@ public abstract class InputExpressionDialog<FormType extends InputForm> extends
|
||||
if (getMode() == Mode.ADVANCED) {
|
||||
return myEditor.getField().getEditor();
|
||||
} else {
|
||||
return myComboboxEditor.getEditor();
|
||||
return myComboBox.getEditorEx();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,35 +403,6 @@ public abstract class InputExpressionDialog<FormType extends InputForm> extends
|
||||
}
|
||||
}
|
||||
|
||||
protected class EditorAdapter extends BasicComboBoxEditor {
|
||||
private final EditorTextField myTf;
|
||||
|
||||
public EditorAdapter(EditorTextField tf) {
|
||||
myTf = tf;
|
||||
}
|
||||
|
||||
public Component getEditorComponent() {
|
||||
return myTf.getComponent();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Object getItem() {
|
||||
return myModel.getSelectedItem();
|
||||
}
|
||||
|
||||
public void selectAll() {
|
||||
myTf.selectAll();
|
||||
}
|
||||
|
||||
public void setItem(Object object) {
|
||||
if (object == null) {
|
||||
myEditor.getField().setText("");
|
||||
} else {
|
||||
myEditor.getField().setText(((HistoryElement)object).expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyVariableResolver extends SimpleVariableContext {
|
||||
private final HistoryModel myModel;
|
||||
|
||||
@@ -568,7 +532,7 @@ public abstract class InputExpressionDialog<FormType extends InputForm> extends
|
||||
|
||||
@NotNull
|
||||
public String getText() {
|
||||
return "Register Namespace Prefix";
|
||||
return "Register namespace prefix";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -27,8 +27,7 @@ setProperty("ch", "$home/community")
|
||||
setProperty("pythonCommunityHome", "$ch/python")
|
||||
setProperty("pythonEduHome", "$ch/python/edu")
|
||||
requireProperty("jdk_bundled_mac", "1.7")
|
||||
def jdk_bundled_version = p("jdk_bundled_mac") == "1.8" ? "jdk8_mac_redist.tar" : "jdk_mac_redist.tar"
|
||||
ant.copy(file: "${home}/build/jdk/${jdk_bundled_version}", tofile: "${home}/build/jdk/jdk_mac_redist_for_${buildNumber}.tar")
|
||||
getBundledJDK(new File("${home}/build/jdk/mac"), "jdk" + p("jdk_bundled_mac"), ".tar", "${home}/build/jdk/jdk_mac_redist_for_${buildNumber}.tar")
|
||||
|
||||
// load ApplicationInfo.xml properties
|
||||
ant.xmlproperty(file: "$pythonEduHome/resources/idea/PyCharmEduApplicationInfo.xml", collapseAttributes: "true")
|
||||
|
||||
@@ -96,6 +96,11 @@ PluginManager = None
|
||||
if SUPPORT_PLUGINS:
|
||||
from pydevd_plugin_utils import PluginManager
|
||||
|
||||
if IS_PY3K:
|
||||
import pkgutil
|
||||
else:
|
||||
from _pydev_imps import _pydev_pkgutil_old as pkgutil
|
||||
|
||||
threadingEnumerate = threading.enumerate
|
||||
threadingCurrentThread = threading.currentThread
|
||||
|
||||
@@ -1684,8 +1689,27 @@ class PyDB:
|
||||
from pydev_monkey import patch_thread_modules
|
||||
patch_thread_modules()
|
||||
|
||||
def get_fullname(self, mod_name):
|
||||
try:
|
||||
loader = pkgutil.get_loader(mod_name)
|
||||
except:
|
||||
return None
|
||||
if loader is not None:
|
||||
for attr in ("get_filename", "_get_filename"):
|
||||
meth = getattr(loader, attr, None)
|
||||
if meth is not None:
|
||||
return meth(mod_name)
|
||||
return None
|
||||
|
||||
def run(self, file, globals=None, locals=None, module=False, set_trace=True):
|
||||
if module:
|
||||
filename = self.get_fullname(file)
|
||||
if filename is None:
|
||||
sys.stderr.write("No module named %s\n" % file)
|
||||
return
|
||||
else:
|
||||
file = filename
|
||||
|
||||
def run(self, file, globals=None, locals=None, set_trace=True):
|
||||
if os.path.isdir(file):
|
||||
new_target = os.path.join(file, '__main__.py')
|
||||
if os.path.isfile(new_target):
|
||||
@@ -1773,6 +1797,7 @@ def processCommandLine(argv):
|
||||
setup['save-signatures'] = False
|
||||
setup['print-in-debugger-startup'] = False
|
||||
setup['cmd-line'] = False
|
||||
setup['module'] = False
|
||||
i = 0
|
||||
del argv[0]
|
||||
while (i < len(argv)):
|
||||
@@ -1816,6 +1841,9 @@ def processCommandLine(argv):
|
||||
elif (argv[i] == '--cmd-line'):
|
||||
del argv[i]
|
||||
setup['cmd-line'] = True
|
||||
elif (argv[i] == '--module'):
|
||||
del argv[i]
|
||||
setup['module'] = True
|
||||
else:
|
||||
raise ValueError("unexpected option " + argv[i])
|
||||
return setup
|
||||
@@ -2256,6 +2284,7 @@ if __name__ == '__main__':
|
||||
pass # It's ok not having stackless there...
|
||||
|
||||
debugger = PyDB()
|
||||
is_module = setup['module']
|
||||
|
||||
if fix_app_engine_debug:
|
||||
sys.stderr.write("pydev debugger: google app engine integration enabled\n")
|
||||
@@ -2270,7 +2299,7 @@ if __name__ == '__main__':
|
||||
sys.argv.insert(4, '--max_module_instances=1')
|
||||
|
||||
# Run the dev_appserver
|
||||
debugger.run(setup['file'], None, None, set_trace=False)
|
||||
debugger.run(setup['file'], None, None, is_module, set_trace=False)
|
||||
else:
|
||||
# as to get here all our imports are already resolved, the psyco module can be
|
||||
# changed and we'll still get the speedups in the debugger, as those functions
|
||||
@@ -2303,7 +2332,7 @@ if __name__ == '__main__':
|
||||
|
||||
connected = True # Mark that we're connected when started from inside ide.
|
||||
|
||||
globals = debugger.run(setup['file'], None, None)
|
||||
globals = debugger.run(setup['file'], None, None, is_module)
|
||||
|
||||
if setup['cmd-line']:
|
||||
debugger.wait_for_commands(globals)
|
||||
|
||||
@@ -66,6 +66,7 @@ public class PyDebugRunner extends GenericProgramRunner {
|
||||
public static final String IDE_PROJECT_ROOTS = "IDE_PROJECT_ROOTS";
|
||||
@SuppressWarnings("SpellCheckingInspection")
|
||||
public static final String GEVENT_SUPPORT = "GEVENT_SUPPORT";
|
||||
public static boolean isModule = false;
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
@@ -182,14 +183,37 @@ public class PyDebugRunner extends GenericProgramRunner {
|
||||
final PythonCommandLineState pyState,
|
||||
final int serverLocalPort) {
|
||||
return new CommandLinePatcher() {
|
||||
|
||||
private void patchExeParams(ParametersList parametersList) {
|
||||
// we should remove '-m' parameter, but notify debugger of it
|
||||
// but we can't remove one parameter from group, so we create new parameters group
|
||||
ParamsGroup newExeParams = new ParamsGroup(PythonCommandLineState.GROUP_EXE_OPTIONS);
|
||||
int exeParamsIndex = parametersList.getParamsGroups().indexOf(
|
||||
parametersList.getParamsGroup(PythonCommandLineState.GROUP_EXE_OPTIONS));
|
||||
ParamsGroup exeParamsOld = parametersList.removeParamsGroup(exeParamsIndex);
|
||||
isModule = false;
|
||||
for (String param: exeParamsOld.getParameters()) {
|
||||
if (!param.equals("-m")) {
|
||||
newExeParams.addParameter(param);
|
||||
} else {
|
||||
isModule = true;
|
||||
}
|
||||
}
|
||||
|
||||
parametersList.addParamsGroupAt(exeParamsIndex, newExeParams);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void patchCommandLine(GeneralCommandLine commandLine) {
|
||||
// script name is the last parameter; all other params are for python interpreter; insert just before name
|
||||
final ParametersList parametersList = commandLine.getParametersList();
|
||||
ParametersList parametersList = commandLine.getParametersList();
|
||||
|
||||
@SuppressWarnings("ConstantConditions") @NotNull
|
||||
ParamsGroup debugParams = parametersList.getParamsGroup(PythonCommandLineState.GROUP_DEBUGGER);
|
||||
|
||||
patchExeParams(parametersList);
|
||||
|
||||
@SuppressWarnings("ConstantConditions") @NotNull
|
||||
ParamsGroup exeParams = parametersList.getParamsGroup(PythonCommandLineState.GROUP_EXE_OPTIONS);
|
||||
|
||||
@@ -218,6 +242,10 @@ public class PyDebugRunner extends GenericProgramRunner {
|
||||
debugParams.addParameter("--multiproc");
|
||||
}
|
||||
|
||||
if (isModule) {
|
||||
debugParams.addParameter("--module");
|
||||
}
|
||||
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
debugParams.addParameter("--DEBUG");
|
||||
}
|
||||
|
||||
@@ -22,26 +22,39 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiComment;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Joins lines sanely.
|
||||
* - statement lines: add a semicolon;
|
||||
* - list-like lines: keep one space after comma;
|
||||
* - lines inside a multiline string: remove excess indentation;
|
||||
* - multi-constant string like "a" "b": join into one;
|
||||
* - comment and comment: remove indentation and hash sign;
|
||||
* - second line is 'class' or 'def': fail.
|
||||
* <br/>
|
||||
* User: dcheryasov
|
||||
* Date: Sep 6, 2010 2:25:48 AM
|
||||
* <ul>
|
||||
* <li>statement lines: add a semicolon;</li>
|
||||
* <li>list-like lines: keep one space after comma;</li>
|
||||
* <li>lines inside a multiline string: remove excess indentation;</li>
|
||||
* <li>multi-constant string like "a" "b": join into one;</li>
|
||||
* <li>comment and comment: remove indentation and hash sign;</li>
|
||||
* <li>second line is 'class' or 'def': fail.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author dcheryasov
|
||||
*/
|
||||
public class PyJoinLinesHandler implements JoinRawLinesHandlerDelegate {
|
||||
private final static Joiner[] JOINERS = {
|
||||
new OpenBracketJoiner(),
|
||||
new CloseBracketJoiner(),
|
||||
new StringLiteralJoiner(),
|
||||
new StmtJoiner(), // strings before stmts to let doc strings join
|
||||
new BinaryExprJoiner(),
|
||||
new CommentJoiner(),
|
||||
new StripBackslashJoiner()
|
||||
};
|
||||
|
||||
|
||||
@Override
|
||||
public int tryJoinLines(Document document, PsiFile file, int start, int end) {
|
||||
@@ -49,203 +62,117 @@ public class PyJoinLinesHandler implements JoinRawLinesHandlerDelegate {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int tryJoinRawLines(Document document, PsiFile file, int start, int end) {
|
||||
public int tryJoinRawLines(@NotNull Document document, PsiFile file, int start, int end) {
|
||||
if (!(file instanceof PyFile)) return CANNOT_JOIN;
|
||||
|
||||
// step back the probable "\" and space before it.
|
||||
int i = start;
|
||||
CharSequence text = document.getCharsSequence();
|
||||
if (i>= 0 && text.charAt(i) == '\n') i -=1;
|
||||
if (i>= 0 && text.charAt(i) == '\\') i -=1;
|
||||
while (i>=0 && text.charAt(i) == ' ' || text.charAt(i) == '\t') i -=1;
|
||||
if (i < 0) return CANNOT_JOIN; // TODO: join with empty BOF, too
|
||||
final CharSequence text = document.getCharsSequence();
|
||||
if (start >= 0 && text.charAt(start) == '\n') start -= 1;
|
||||
if (start >= 0 && text.charAt(start) == '\\') start -= 1;
|
||||
while (start >= 0 && text.charAt(start) == ' ' || text.charAt(start) == '\t') {
|
||||
start -= 1;
|
||||
}
|
||||
if (start < 0) {
|
||||
return CANNOT_JOIN; // TODO: join with empty BOF, too
|
||||
}
|
||||
|
||||
// detect elements around the join
|
||||
PsiElement left_element = file.findElementAt(i);
|
||||
PsiElement right_element = file.findElementAt(end);
|
||||
if (left_element != null && right_element != null) {
|
||||
PyExpression left_expr = PsiTreeUtil.getParentOfType(left_element, PyExpression.class);
|
||||
if (left_expr instanceof PsiFile) left_expr = null;
|
||||
PyExpression right_expr = PsiTreeUtil.getParentOfType(right_element, PyExpression.class);
|
||||
if (right_expr instanceof PsiFile) right_expr = null;
|
||||
final PsiElement leftElement = file.findElementAt(start);
|
||||
final PsiElement rightElement = file.findElementAt(end);
|
||||
if (leftElement != null && rightElement != null) {
|
||||
final PyExpression leftExpr = PsiTreeUtil.getParentOfType(leftElement, PyExpression.class);
|
||||
final PyExpression rightExpr = PsiTreeUtil.getParentOfType(rightElement, PyExpression.class);
|
||||
|
||||
Joiner[] joiners = { // these are featherweight, will create and gc instantly
|
||||
new OpenBracketJoiner(), new CloseBracketJoiner(),
|
||||
new StringLiteralJoiner(), new StmtJoiner(), // strings before stmts to let doc strings join
|
||||
new BinaryExprJoiner(), new ListLikeExprJoiner(),
|
||||
new CommentJoiner(),
|
||||
};
|
||||
final Request request = new Request(document, start, end, leftElement, leftExpr, rightElement, rightExpr);
|
||||
|
||||
Request request = new Request(document, left_element, left_expr, right_element, right_expr);
|
||||
|
||||
for (Joiner joiner : joiners) {
|
||||
Result res = joiner.join(request);
|
||||
for (Joiner joiner : JOINERS) {
|
||||
final Result res = joiner.join(request);
|
||||
if (res != null) {
|
||||
final int cut_start = i + 1 - res.getCutFromLeft();
|
||||
document.deleteString(cut_start, end + res.getCutIntoRight());
|
||||
document.insertString(cut_start, res.getInsert());
|
||||
return cut_start + res.getCursorOffset();
|
||||
}
|
||||
}
|
||||
|
||||
// single string case PY-4375
|
||||
final PyExpression leftExpression = request.leftExpr();
|
||||
final PyExpression rightExpression = request.rightExpr();
|
||||
if (request.leftElem() == request.rightElem()) {
|
||||
IElementType type = request.leftElem().getNode().getElementType();
|
||||
if (PyTokenTypes.SINGLE_QUOTED_STRING == type || PyTokenTypes.SINGLE_QUOTED_UNICODE == type) {
|
||||
if (leftExpression == null) return CANNOT_JOIN;
|
||||
if (removeBackSlash(document, leftExpression, false)) {
|
||||
return leftExpression.getTextOffset();
|
||||
}
|
||||
}
|
||||
}
|
||||
PsiElement expression = null;
|
||||
if (leftExpression != null && rightExpression != null) {
|
||||
if (PsiTreeUtil.isAncestor(leftExpression, rightExpression, false))
|
||||
expression = leftExpression;
|
||||
else if (PsiTreeUtil.isAncestor(rightExpression, leftExpression, false))
|
||||
expression = rightExpression;
|
||||
if (expression != null && !(expression instanceof PyStringLiteralExpression)) {
|
||||
if (removeBackSlash(document, expression, true)) {
|
||||
return expression.getTextOffset();
|
||||
}
|
||||
final int cutStart = start + 1 - res.cutFromLeft;
|
||||
document.replaceString(cutStart, end + res.cutIntoRight, res.replacement);
|
||||
return cutStart + res.caretOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
return CANNOT_JOIN;
|
||||
}
|
||||
|
||||
private static boolean removeBackSlash(Document document, PsiElement element, boolean trim) {
|
||||
String[] substrings = element.getText().split("\n");
|
||||
if (substrings.length != 1) {
|
||||
StringBuilder replacement = new StringBuilder();
|
||||
for (int i = 0; i < substrings.length; i++) {
|
||||
String string = substrings[i];
|
||||
if (trim) {
|
||||
string = StringUtil.trimLeading(string);
|
||||
}
|
||||
if (string.trim().endsWith("\\")) {
|
||||
replacement.append(string.substring(0, string.length() - 1));
|
||||
}
|
||||
else {
|
||||
replacement.append(string);
|
||||
}
|
||||
|
||||
if (i != substrings.length - 1 && !(element instanceof PyReferenceExpression) &&
|
||||
!(element instanceof PyStringLiteralExpression)) {
|
||||
replacement.append(" ");
|
||||
}
|
||||
}
|
||||
document.replaceString(element.getTextOffset(), element.getTextOffset()+element.getTextLength(), replacement);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// a dumb immutable result holder
|
||||
private static class Result {
|
||||
final String myInsert;
|
||||
final int myOffset;
|
||||
final int myCutFromLeft;
|
||||
final int myCutIntoRight;
|
||||
final String replacement;
|
||||
final int caretOffset;
|
||||
final int cutFromLeft;
|
||||
final int cutIntoRight;
|
||||
|
||||
/**
|
||||
* Result of a join operation.
|
||||
* @param insert: what string to insert at start position
|
||||
*
|
||||
* @param replacement: what string to insert at start position
|
||||
* @param cursorOffset: how to move cursor relative to start (0 = stand at start)
|
||||
*/
|
||||
Result(String insert, int cursorOffset) {
|
||||
myInsert = insert;
|
||||
myOffset = cursorOffset;
|
||||
myCutFromLeft = 0;
|
||||
myCutIntoRight = 0;
|
||||
Result(@NotNull String replacement, int cursorOffset) {
|
||||
this(replacement, cursorOffset, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Result of a join operation.
|
||||
* @param insert what to insert into the cut place
|
||||
*
|
||||
* @param replacement what to insert into the cut place
|
||||
* @param cursorOffset where to put cursor, relative to the start cursorOffset of cutting
|
||||
* @param cutFromLeft how many chars to cut from the end on left string, >0 moves start cursorOffset of cutting to the left.
|
||||
* @param cutFromLeft how many chars to cut from the end on left string, >0 moves start cursorOffset of cutting to the left.
|
||||
* @param cutIntoRight how many chars to cut from the beginning on right string, >0 moves start cursorOffset of cutting to the right.
|
||||
*/
|
||||
private Result(String insert, int cursorOffset, int cutFromLeft, int cutIntoRight) {
|
||||
myCutFromLeft = cutFromLeft;
|
||||
myCutIntoRight = cutIntoRight;
|
||||
myInsert = insert;
|
||||
myOffset = cursorOffset;
|
||||
}
|
||||
|
||||
public String getInsert() {
|
||||
return myInsert;
|
||||
}
|
||||
|
||||
public int getCursorOffset() {
|
||||
return myOffset;
|
||||
}
|
||||
|
||||
public int getCutFromLeft() {
|
||||
return myCutFromLeft;
|
||||
}
|
||||
|
||||
public int getCutIntoRight() {
|
||||
return myCutIntoRight;
|
||||
Result(@NotNull String replacement, int cursorOffset, int cutFromLeft, int cutIntoRight) {
|
||||
this.cutFromLeft = cutFromLeft;
|
||||
this.cutIntoRight = cutIntoRight;
|
||||
this.replacement = replacement;
|
||||
caretOffset = cursorOffset;
|
||||
}
|
||||
}
|
||||
|
||||
// a dumb immutable request items holder
|
||||
private static class Request {
|
||||
final Document myDocument;
|
||||
final PsiElement myLeftElem;
|
||||
final PsiElement myRightElem;
|
||||
final PyExpression myLeftExpr;
|
||||
final PyExpression myRightExpr;
|
||||
final Document document;
|
||||
final PsiElement leftElem;
|
||||
final PsiElement rightElem;
|
||||
final PyExpression leftExpr;
|
||||
final PyExpression rightExpr;
|
||||
final int secondLineStartOffset;
|
||||
final int firstLineEndOffset;
|
||||
|
||||
private Request(Document document, PsiElement leftElem, PyExpression leftExpr, PsiElement rightElem, PyExpression rightExpr) {
|
||||
myDocument = document;
|
||||
myLeftElem = leftElem;
|
||||
myLeftExpr = leftExpr;
|
||||
myRightElem = rightElem;
|
||||
myRightExpr = rightExpr;
|
||||
private Request(@NotNull Document document,
|
||||
int firstLineEndOffset,
|
||||
int secondLineStartOffset,
|
||||
@NotNull PsiElement leftElem,
|
||||
@Nullable PyExpression leftExpr,
|
||||
@NotNull PsiElement rightElem,
|
||||
@Nullable PyExpression rightExpr) {
|
||||
this.document = document;
|
||||
this.firstLineEndOffset = firstLineEndOffset;
|
||||
this.secondLineStartOffset = secondLineStartOffset;
|
||||
this.leftElem = leftElem;
|
||||
this.rightElem = rightElem;
|
||||
this.leftExpr = leftExpr;
|
||||
this.rightExpr = rightExpr;
|
||||
}
|
||||
|
||||
public Document document() {
|
||||
return myDocument;
|
||||
}
|
||||
|
||||
public PsiElement leftElem() {
|
||||
return myLeftElem;
|
||||
}
|
||||
|
||||
public PyExpression leftExpr() {
|
||||
return myLeftExpr;
|
||||
}
|
||||
|
||||
public PsiElement rightElem() {
|
||||
return myRightElem;
|
||||
}
|
||||
|
||||
public PyExpression rightExpr() {
|
||||
return myRightExpr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static abstract class Joiner {
|
||||
private interface Joiner {
|
||||
/**
|
||||
* Try to join lines.
|
||||
*
|
||||
* @param req@return null if cannot join, or ("what to insert", cursor_offset).
|
||||
*/
|
||||
@Nullable
|
||||
abstract public Result join(Request req);
|
||||
Result join(@NotNull Request req);
|
||||
}
|
||||
|
||||
private static class OpenBracketJoiner extends Joiner {
|
||||
private static TokenSet OPENS = TokenSet.create(PyTokenTypes.LBRACKET, PyTokenTypes.LBRACE, PyTokenTypes.LPAR);
|
||||
private static class OpenBracketJoiner implements Joiner {
|
||||
private static final TokenSet OPENS = TokenSet.create(PyTokenTypes.LBRACKET, PyTokenTypes.LBRACE, PyTokenTypes.LPAR);
|
||||
|
||||
@Override
|
||||
public Result join(Request req) {
|
||||
if (OPENS.contains(req.leftElem().getNode().getElementType())) {
|
||||
public Result join(@NotNull Request req) {
|
||||
if (OPENS.contains(req.leftElem.getNode().getElementType())) {
|
||||
// TODO: look at settings for space after opening paren
|
||||
return new Result("", 0);
|
||||
}
|
||||
@@ -253,11 +180,12 @@ public class PyJoinLinesHandler implements JoinRawLinesHandlerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
private static class CloseBracketJoiner extends Joiner {
|
||||
private static TokenSet CLOSES = TokenSet.create(PyTokenTypes.RBRACKET, PyTokenTypes.RBRACE, PyTokenTypes.RPAR);
|
||||
private static class CloseBracketJoiner implements Joiner {
|
||||
private static final TokenSet CLOSES = TokenSet.create(PyTokenTypes.RBRACKET, PyTokenTypes.RBRACE, PyTokenTypes.RPAR);
|
||||
|
||||
@Override
|
||||
public Result join(Request req) {
|
||||
if (CLOSES.contains(req.rightElem().getNode().getElementType())) {
|
||||
public Result join(@NotNull Request req) {
|
||||
if (CLOSES.contains(req.rightElem.getNode().getElementType())) {
|
||||
// TODO: look at settings for space before closing paren
|
||||
return new Result("", 0);
|
||||
}
|
||||
@@ -265,10 +193,10 @@ public class PyJoinLinesHandler implements JoinRawLinesHandlerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
private static class BinaryExprJoiner extends Joiner {
|
||||
private static class BinaryExprJoiner implements Joiner {
|
||||
@Override
|
||||
public Result join(Request req) {
|
||||
if (req.leftExpr() instanceof PyBinaryExpression || req.rightExpr() instanceof PyBinaryExpression) {
|
||||
public Result join(@NotNull Request req) {
|
||||
if (req.leftExpr instanceof PyBinaryExpression || req.rightExpr instanceof PyBinaryExpression) {
|
||||
// TODO: look at settings for space around binary exprs
|
||||
return new Result(" ", 1);
|
||||
}
|
||||
@@ -276,29 +204,13 @@ public class PyJoinLinesHandler implements JoinRawLinesHandlerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
private static class ListLikeExprJoiner extends Joiner {
|
||||
private static class StmtJoiner implements Joiner {
|
||||
@Override
|
||||
public Result join(Request req) {
|
||||
final boolean left_is_list_like = PyUtil.instanceOf(req.leftExpr(), PyListLiteralExpression.class, PyTupleExpression.class);
|
||||
if (left_is_list_like || PyUtil.instanceOf(req.rightExpr(), PyListLiteralExpression.class, PyTupleExpression.class)
|
||||
) {
|
||||
String insert = "";
|
||||
if (left_is_list_like) { // we join "a, \n b", not "a \n ,b"
|
||||
insert = " "; // TODO: look at settings for space after commas in lists
|
||||
}
|
||||
return new Result(insert, insert.length());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class StmtJoiner extends Joiner {
|
||||
@Override
|
||||
public Result join(Request req) {
|
||||
PyStatement left_stmt = PsiTreeUtil.getParentOfType(req.leftExpr(), PyStatement.class);
|
||||
if (left_stmt != null) {
|
||||
PyStatement right_stmt = PsiTreeUtil.getParentOfType(req.rightExpr(), PyStatement.class);
|
||||
if (right_stmt != null && right_stmt != left_stmt) {
|
||||
public Result join(@NotNull Request req) {
|
||||
final PyStatement leftStmt = PsiTreeUtil.getParentOfType(req.leftExpr, PyStatement.class);
|
||||
if (leftStmt != null) {
|
||||
final PyStatement rightStmt = PsiTreeUtil.getParentOfType(req.rightExpr, PyStatement.class);
|
||||
if (rightStmt != null && rightStmt != leftStmt) {
|
||||
// TODO: look at settings for space after semicolon
|
||||
return new Result("; ", 1); // cursor after semicolon
|
||||
}
|
||||
@@ -307,34 +219,33 @@ public class PyJoinLinesHandler implements JoinRawLinesHandlerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
private static class StringLiteralJoiner extends Joiner {
|
||||
private static class StringLiteralJoiner implements Joiner {
|
||||
@Override
|
||||
public Result join(Request req) {
|
||||
if (req.leftElem() != req.rightElem()) {
|
||||
final PsiElement parent = req.rightElem().getParent();
|
||||
if ((req.leftElem().getParent() == parent && parent instanceof PyStringLiteralExpression) ||
|
||||
(req.leftExpr() instanceof PyStringLiteralExpression && req.rightExpr() instanceof PyStringLiteralExpression)
|
||||
) {
|
||||
public Result join(@NotNull Request req) {
|
||||
if (req.leftElem != req.rightElem) {
|
||||
final PsiElement parent = req.rightElem.getParent();
|
||||
if ((req.leftElem.getParent() == parent && parent instanceof PyStringLiteralExpression) ||
|
||||
(req.leftExpr instanceof PyStringLiteralExpression && req.rightExpr instanceof PyStringLiteralExpression)) {
|
||||
// two quoted strings close by
|
||||
CharSequence text = req.document().getCharsSequence();
|
||||
StrMod left_mod = new StrMod(text, req.leftElem().getTextRange());
|
||||
StrMod right_mod = new StrMod(text, req.rightElem().getTextRange());
|
||||
if (left_mod.isOk() && right_mod.isOk()) {
|
||||
final String lquo = left_mod.quote();
|
||||
if (left_mod.equals(right_mod)) {
|
||||
return new Result("", 0, lquo.length(), right_mod.getStartPadding());
|
||||
final CharSequence text = req.document.getCharsSequence();
|
||||
final StrMod leftMod = new StrMod(text, req.leftElem.getTextRange());
|
||||
final StrMod rightMod = new StrMod(text, req.rightElem.getTextRange());
|
||||
if (leftMod.isOk() && rightMod.isOk()) {
|
||||
final String lquo = leftMod.quote();
|
||||
if (leftMod.equals(rightMod)) {
|
||||
return new Result("", 0, lquo.length(), rightMod.getStartPadding());
|
||||
}
|
||||
else if (left_mod.compatibleTo(right_mod) && lquo.length() == 1 && right_mod.quote().length() == 1) {
|
||||
else if (leftMod.compatibleTo(rightMod) && lquo.length() == 1 && rightMod.quote().length() == 1) {
|
||||
// maybe fit one literal's quotes to match other's
|
||||
if (! containsChar(text, right_mod.getInnerRange(), left_mod.quote().charAt(0))) {
|
||||
int quote_pos = right_mod.getInnerRange().getEndOffset();
|
||||
req.document().replaceString(quote_pos, quote_pos+1, left_mod.quote());
|
||||
return new Result("", 0, left_mod.quote().length(), right_mod.getStartPadding());
|
||||
if (!containsChar(text, rightMod.getInnerRange(), leftMod.quote().charAt(0))) {
|
||||
final int quotePos = rightMod.getInnerRange().getEndOffset();
|
||||
req.document.replaceString(quotePos, quotePos + 1, leftMod.quote());
|
||||
return new Result("", 0, leftMod.quote().length(), rightMod.getStartPadding());
|
||||
}
|
||||
else if (! containsChar(text, left_mod.getInnerRange(), right_mod.quote().charAt(0))) {
|
||||
int quote_pos = left_mod.getInnerRange().getStartOffset()-1;
|
||||
req.document().replaceString(quote_pos, quote_pos+1, right_mod.quote());
|
||||
return new Result("", 0, left_mod.quote().length(), right_mod.getStartPadding());
|
||||
else if (!containsChar(text, leftMod.getInnerRange(), rightMod.quote().charAt(0))) {
|
||||
final int quotePos = leftMod.getInnerRange().getStartOffset() - 1;
|
||||
req.document.replaceString(quotePos, quotePos + 1, rightMod.quote());
|
||||
return new Result("", 0, leftMod.quote().length(), rightMod.getStartPadding());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -343,71 +254,71 @@ public class PyJoinLinesHandler implements JoinRawLinesHandlerDelegate {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static boolean containsChar(CharSequence text, TextRange range, char c) {
|
||||
for (int i=range.getStartOffset(); i <= range.getEndOffset(); i+=1) {
|
||||
if (text.charAt(i) == c) return true;
|
||||
}
|
||||
return false;
|
||||
protected static boolean containsChar(@NotNull CharSequence text, @NotNull TextRange range, char c) {
|
||||
return StringUtil.contains(text, range.getStartOffset(), range.getEndOffset(), c);
|
||||
}
|
||||
|
||||
private static class StrMod {
|
||||
private final String myPrefix; // "u", "b", or ""
|
||||
private final boolean myRaw; // is raw or not
|
||||
private final String myQuote; // single or double, one or triple.
|
||||
private final boolean myOk; // true if parsing went ok
|
||||
private final TextRange myInnerRange;
|
||||
|
||||
public StrMod(CharSequence text, TextRange range) {
|
||||
private static class StrMod {
|
||||
@NotNull private final String myPrefix; // "u", "b", or ""
|
||||
private final boolean myRaw; // is raw or not
|
||||
@NotNull private final String myQuote; // single or double, one or triple.
|
||||
|
||||
@Nullable private final TextRange myInnerRange;
|
||||
|
||||
public StrMod(@NotNull CharSequence text, @NotNull TextRange range) {
|
||||
int pos = range.getStartOffset();
|
||||
char c = text.charAt(pos);
|
||||
if ("Uu".indexOf(c) > -1 || "Bb".indexOf(c) > -1) {
|
||||
myPrefix = String.valueOf(c).toLowerCase();
|
||||
pos +=1;
|
||||
myPrefix = String.valueOf(c).toLowerCase(Locale.US);
|
||||
pos += 1;
|
||||
c = text.charAt(pos);
|
||||
}
|
||||
else myPrefix = "";
|
||||
else {
|
||||
myPrefix = "";
|
||||
}
|
||||
if ("Rr".indexOf(c) > -1) {
|
||||
myRaw = true;
|
||||
pos +=1;
|
||||
pos += 1;
|
||||
c = text.charAt(pos);
|
||||
}
|
||||
else myRaw = false;
|
||||
char quote = c;
|
||||
else {
|
||||
myRaw = false;
|
||||
}
|
||||
final char quote = c;
|
||||
if ("'\"".indexOf(quote) < 0) {
|
||||
myInnerRange = null;
|
||||
myQuote = "";
|
||||
myOk = false;
|
||||
return; // failed to find a quote
|
||||
}
|
||||
// TODO: we could run a simple but complete parser here, only checking escapes
|
||||
if (range.getLength() >= 6 && text.charAt(pos+1) == quote && text.charAt(pos+2) == quote) {
|
||||
myQuote = text.subSequence(pos, pos+3).toString();
|
||||
if (!myQuote.equals(text.subSequence(range.getEndOffset()-3, range.getEndOffset()).toString())) {
|
||||
if (range.getLength() >= 6 && text.charAt(pos + 1) == quote && text.charAt(pos + 2) == quote) {
|
||||
myQuote = text.subSequence(pos, pos + 3).toString();
|
||||
if (!myQuote.equals(text.subSequence(range.getEndOffset() - 3, range.getEndOffset()).toString())) {
|
||||
myInnerRange = null;
|
||||
myOk = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
myQuote = text.subSequence(pos, pos+1).toString();
|
||||
if (!myQuote.equals(text.subSequence(range.getEndOffset()-1, range.getEndOffset()).toString())) {
|
||||
myQuote = text.subSequence(pos, pos + 1).toString();
|
||||
if (!myQuote.equals(text.subSequence(range.getEndOffset() - 1, range.getEndOffset()).toString())) {
|
||||
myInnerRange = null;
|
||||
myOk = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
myInnerRange = TextRange.from(range.getStartOffset()+getStartPadding(), range.getLength()-getStartPadding()-quote().length());
|
||||
myOk = true;
|
||||
myInnerRange = TextRange.from(range.getStartOffset() + getStartPadding(), range.getLength() - getStartPadding() - quote().length());
|
||||
}
|
||||
|
||||
public boolean isOk() {
|
||||
return myOk;
|
||||
return myInnerRange != null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String prefix() {
|
||||
return myPrefix;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String quote() {
|
||||
return myQuote;
|
||||
}
|
||||
@@ -420,12 +331,7 @@ public class PyJoinLinesHandler implements JoinRawLinesHandlerDelegate {
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof StrMod) {
|
||||
final StrMod other = (StrMod)o;
|
||||
return (
|
||||
myOk && other.isOk() &&
|
||||
myRaw == other.isRaw() &&
|
||||
myPrefix.equals(other.prefix()) &&
|
||||
myQuote.equals(other.quote())
|
||||
);
|
||||
return compatibleTo(other) && myQuote.equals(other.quote());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -434,44 +340,60 @@ public class PyJoinLinesHandler implements JoinRawLinesHandlerDelegate {
|
||||
* @return combined length of initial modifier letters and opening quotes
|
||||
*/
|
||||
public int getStartPadding() {
|
||||
return myQuote.length() + myPrefix.length() + (myRaw? 1 : 0);
|
||||
return myQuote.length() + myPrefix.length() + (myRaw ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param other
|
||||
* @return true iff this and other have the same byte/unicode and raw prefixes.
|
||||
*/
|
||||
public boolean compatibleTo(StrMod other) {
|
||||
return myOk && other.isOk() && myRaw == other.isRaw() && myPrefix.equals(other.prefix());
|
||||
public boolean compatibleTo(@NotNull StrMod other) {
|
||||
return isOk() && other.isOk() && myRaw == other.isRaw() && myPrefix.equals(other.prefix());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return range of text part inside quotes
|
||||
*/
|
||||
@Nullable
|
||||
public TextRange getInnerRange() {
|
||||
return myInnerRange;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static class CommentJoiner extends Joiner {
|
||||
private static class CommentJoiner implements Joiner {
|
||||
@Override
|
||||
public Result join(Request req) {
|
||||
if (req.leftElem() instanceof PsiComment && req.rightElem() instanceof PsiComment) {
|
||||
CharSequence text = req.document().getCharsSequence();
|
||||
final TextRange right_range = req.rightElem().getTextRange();
|
||||
int initial_pos = right_range.getStartOffset() + 1;
|
||||
int pos = initial_pos; // cut '#'
|
||||
int last = right_range.getEndOffset();
|
||||
public Result join(@NotNull Request req) {
|
||||
if (req.leftElem instanceof PsiComment && req.rightElem instanceof PsiComment) {
|
||||
final CharSequence text = req.document.getCharsSequence();
|
||||
final TextRange rightRange = req.rightElem.getTextRange();
|
||||
final int initialPos = rightRange.getStartOffset() + 1;
|
||||
int pos = initialPos; // cut '#'
|
||||
final int last = rightRange.getEndOffset();
|
||||
while (pos < last && " \t".indexOf(text.charAt(pos)) >= 0) pos += 1;
|
||||
int right = pos - initial_pos + 1; // account for the '#'
|
||||
final int right = pos - initialPos + 1; // account for the '#'
|
||||
return new Result(" ", 0, 0, right);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class StripBackslashJoiner implements Joiner {
|
||||
static final TokenSet SINGLE_QUOTED_STRINGS = TokenSet.create(PyTokenTypes.SINGLE_QUOTED_STRING, PyTokenTypes.SINGLE_QUOTED_UNICODE);
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Result join(@NotNull Request req) {
|
||||
final String gap = req.document.getText(new TextRange(req.firstLineEndOffset + 1, req.secondLineStartOffset));
|
||||
final int index = gap.indexOf('\\');
|
||||
if (index >= 0) {
|
||||
if (req.leftElem == req.rightElem && SINGLE_QUOTED_STRINGS.contains(req.leftElem.getNode().getElementType())) {
|
||||
return new Result(gap.replaceFirst("\\\\\\n", ""), 0);
|
||||
}
|
||||
else {
|
||||
return new Result(gap.substring(0, index), 0);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
from foo import bar, baz
|
||||
@@ -0,0 +1,2 @@
|
||||
from foo import bar, \
|
||||
baz
|
||||
@@ -0,0 +1 @@
|
||||
import foo, bar
|
||||
@@ -0,0 +1,2 @@
|
||||
import foo, \
|
||||
bar
|
||||
@@ -1,2 +1 @@
|
||||
if True:
|
||||
return "No special handling"
|
||||
if True: return "No special handling"
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
a = 1 # surprise!
|
||||
b = 2
|
||||
a = 1 # surprise! b = 2
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
print (r"See, \n separates two lines: "
|
||||
"this and\nthe other")
|
||||
print (r"See, \n separates two lines: " "this and\nthe other")
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
a = (u"Ein Deutsche Text. "
|
||||
"An English text")
|
||||
a = (u"Ein Deutsche Text. " "An English text")
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
<caret>'''This doc comment
|
||||
is quite separate'''
|
||||
'''This doc comment is quite separate'''
|
||||
"""from the literal below"""
|
||||
|
||||
@@ -15,70 +15,137 @@
|
||||
*/
|
||||
package com.jetbrains.python;
|
||||
|
||||
import com.intellij.codeInsight.editorActions.JoinRawLinesHandlerDelegate;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.jetbrains.python.editor.PyJoinLinesHandler;
|
||||
import com.intellij.openapi.actionSystem.IdeActions;
|
||||
import com.jetbrains.python.fixtures.PyTestCase;
|
||||
|
||||
/**
|
||||
* Tests the "Join lines" handler.
|
||||
* <br/>
|
||||
* User: dcheryasov
|
||||
* Date: 1/29/11 2:33 AM
|
||||
*
|
||||
* @author dcheryasov
|
||||
*/
|
||||
public class PyJoinLinesTest extends PyTestCase {
|
||||
private void doTest() {
|
||||
final String path = "joinLines/";
|
||||
myFixture.configureByFile(path + getTestName(false) + ".py");
|
||||
// detect whitespace around EOL, the way JoinLinesHandler does.
|
||||
final Editor editor = myFixture.getEditor();
|
||||
final Document doc = editor.getDocument();
|
||||
final int caret_line = doc.getLineNumber(editor.getCaretModel().getOffset());
|
||||
final int eol_pos = doc.getLineEndOffset(caret_line);
|
||||
CharSequence text = doc.getCharsSequence();
|
||||
int i = eol_pos;
|
||||
while (" \n\t".indexOf(text.charAt(i)) >= 0) i -= 1;
|
||||
final int start = i+1;
|
||||
i = eol_pos;
|
||||
while (" \n\t".indexOf(text.charAt(i)) >= 0) i += 1;
|
||||
final int end = i;
|
||||
final JoinRawLinesHandlerDelegate handler = new PyJoinLinesHandler();
|
||||
WriteCommandAction.runWriteCommandAction(myFixture.getProject(), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
handler.tryJoinRawLines(doc, myFixture.getFile(), start, end);
|
||||
}
|
||||
});
|
||||
myFixture.checkResultByFile(path + getTestName(false) + "-after.py");
|
||||
myFixture.configureByFile("joinLines/" + getTestName(false) + ".py");
|
||||
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_JOIN_LINES);
|
||||
myFixture.checkResultByFile("joinLines/" + getTestName(false) + "-after.py");
|
||||
}
|
||||
|
||||
public void testBinaryOpBelow() { doTest(); }
|
||||
public void testBinaryOp() { doTest(); }
|
||||
public void testDictLCurly() { doTest(); }
|
||||
public void testDictRCurly() { doTest(); }
|
||||
public void testListLBracket() { doTest(); }
|
||||
public void testList() { doTest(); }
|
||||
public void testListRBracket() { doTest(); }
|
||||
public void testStatementColon() { doTest(); }
|
||||
public void testStatementComment() { doTest(); }
|
||||
public void testStatementCommentStatement() { doTest(); }
|
||||
public void testStringDifferentOneQuotes() { doTest(); }
|
||||
public void testStringDifferentOneQuotesBelow() { doTest(); }
|
||||
public void testStringOneQuoteEscEOL() { doTest(); }
|
||||
public void testStringOneQuotePlainRaw() { doTest(); }
|
||||
public void testStringOneQuotePlainU() { doTest(); }
|
||||
public void testStringTripleQuotesDifferent() { doTest(); }
|
||||
public void testStringTripleQuotes() { doTest(); }
|
||||
public void testTupleLPar() { doTest(); }
|
||||
public void testTuple() { doTest(); }
|
||||
public void testTupleRPar() { doTest(); }
|
||||
public void testTwoComments() { doTest(); }
|
||||
public void testTwoComments2() { doTest(); } // PY-7286
|
||||
public void testTwoStatements() { doTest(); }
|
||||
public void testStringWithSlash() { doTest(); }
|
||||
public void testListOfStrings() { doTest(); }
|
||||
public void testLongExpression() { doTest(); }
|
||||
public void testListComprehension() { doTest(); }
|
||||
public void testBinaryOpBelow() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testBinaryOp() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testDictLCurly() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testDictRCurly() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testListLBracket() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testList() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testListRBracket() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testStatementColon() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testStatementComment() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testStatementCommentStatement() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testStringDifferentOneQuotes() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testStringDifferentOneQuotesBelow() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testStringOneQuoteEscEOL() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testStringOneQuotePlainRaw() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testStringOneQuotePlainU() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testStringTripleQuotesDifferent() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testStringTripleQuotes() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testTupleLPar() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testTuple() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testTupleRPar() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testTwoComments() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-7286
|
||||
public void testTwoComments2() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testTwoStatements() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testStringWithSlash() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testListOfStrings() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testLongExpression() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testListComprehension() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-15564
|
||||
public void testBackslashBetweenTargetsInImport() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-15564
|
||||
public void testBackslashBetweenTargetsInFromImport() {
|
||||
doTest();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user