Merge remote-tracking branch 'origin/master'

This commit is contained in:
Roman Shevchenko
2017-03-13 17:39:01 +01:00
58 changed files with 828 additions and 304 deletions
@@ -477,6 +477,7 @@ public class NullableStuffInspectionBase extends BaseJavaBatchLocalInspectionToo
private boolean isNonAnnotatedOverridingNotNull(PsiMethod method, PsiMethod superMethod) {
return REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL &&
!(method.getReturnType() instanceof PsiPrimitiveType) &&
!method.isConstructor() &&
!getNullityManager(method).hasNullability(method) &&
isNotNullNotInferred(superMethod, true, IGNORE_EXTERNAL_SUPER_NOTNULL);
}
@@ -985,8 +985,8 @@ public class ExpectedTypesProvider {
PsiSubstitutor substitutor;
if (candidateInfo instanceof MethodCandidateInfo) {
final MethodCandidateInfo info = (MethodCandidateInfo)candidateInfo;
substitutor = MethodCandidateInfo.ourOverloadGuard
.doPreventingRecursion(argumentList, false, () -> info.inferTypeArguments(policy, args, true));
substitutor = MethodCandidateInfo.ourOverloadGuard.doPreventingRecursion(argumentList, false,
() -> info.inferSubstitutorFromArgs(policy, args));
if (!info.isStaticsScopeCorrect() && !method.hasModifierProperty(PsiModifier.STATIC)) continue;
}
else {
@@ -999,8 +999,7 @@ public class ExpectedTypesProvider {
if (leftArgs != null && candidateInfo instanceof MethodCandidateInfo) {
substitutor = MethodCandidateInfo.ourOverloadGuard.doPreventingRecursion(argumentList, false,
() -> ((MethodCandidateInfo)candidateInfo)
.inferTypeArguments(policy, leftArgs, true));
() -> ((MethodCandidateInfo)candidateInfo).inferSubstitutorFromArgs(policy, leftArgs));
if (substitutor != null) {
inferMethodCallArgumentTypes(argument, forCompletion, leftArgs, index, method, substitutor, array);
}
@@ -806,7 +806,8 @@ public class JavaCompletionUtil {
PsiElement composite = leaf == null ? null : leaf.getParent();
if (composite instanceof PsiMethodReferenceExpression && LambdaHighlightingUtil.insertSemicolon(composite.getParent())) {
insertAdditionalSemicolon = false;
} else if (composite instanceof PsiReferenceExpression) {
}
else if (composite instanceof PsiReferenceExpression) {
PsiElement parent = composite.getParent();
if (parent instanceof PsiMethodCallExpression) {
parent = parent.getParent();
@@ -814,6 +815,9 @@ public class JavaCompletionUtil {
if (parent instanceof PsiLambdaExpression && !LambdaHighlightingUtil.insertSemicolonAfter((PsiLambdaExpression)parent)) {
insertAdditionalSemicolon = false;
}
if (parent instanceof PsiMethodReferenceExpression && LambdaHighlightingUtil.insertSemicolon(parent.getParent())) {
insertAdditionalSemicolon = false;
}
}
if (insertAdditionalSemicolon) {
toInsert = TailType.SEMICOLON;
@@ -159,7 +159,7 @@ public class JavaInheritorsGetter extends CompletionProvider<CompletionParameter
}
try {
final PsiStatement statement = elementFactory
.createStatementFromText(canonicalText + " v = new " + erasedText + "<>()", parameters.getOriginalFile());
.createStatementFromText(canonicalText + " v = new " + erasedText + "<>()", parameters.getPosition());
final PsiVariable declaredVar = (PsiVariable)((PsiDeclarationStatement)statement).getDeclaredElements()[0];
final PsiNewExpression initializer = (PsiNewExpression)declaredVar.getInitializer();
final boolean hasDefaultConstructorOrNoGenericsOne = PsiDiamondTypeImpl.hasDefaultConstructor(psiClass) ||
@@ -102,8 +102,11 @@ public class RedundantArrayForVarargsCallInspection extends GenericsInspectionTo
}
PsiExpression lastArg = args[args.length - 1];
PsiParameter lastParameter = parameters[args.length - 1];
if (!lastParameter.isVarArgs()) {
return;
}
PsiType lastParamType = lastParameter.getType();
LOG.assertTrue(lastParamType instanceof PsiEllipsisType);
LOG.assertTrue(lastParamType instanceof PsiEllipsisType, lastParamType);
if (!(lastArg instanceof PsiNewExpression)) {
return;
}
@@ -32,6 +32,8 @@ import com.intellij.codeInsight.navigation.NavigationUtil;
import com.intellij.ide.util.PsiClassListCellRenderer;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.TransactionGuard;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
@@ -477,9 +479,23 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase {
Util.analyzeExpression(myExpr, new ArrayList<>(), classMemberRefs, new ArrayList<>());
}
showDialog(method, methodToSearchFor, occurences, replaceAllOccurrences, delegate, initializerType, mustBeFinal,
classMemberRefs, createNameSuggestionGenerator(myExpr, propName, myProject, enteredName));
}
}
private void showDialog(PsiMethod method,
PsiMethod methodToSearchFor,
PsiExpression[] occurences,
boolean replaceAllOccurrences,
boolean delegate,
PsiType initializerType,
boolean mustBeFinal,
List<UsageInfo> classMemberRefs, NameSuggestionsGenerator nameSuggestionGenerator) {
TransactionGuard.getInstance().submitTransactionAndWait(() -> {
final IntroduceParameterDialog dialog =
new IntroduceParameterDialog(myProject, classMemberRefs, occurences, myLocalVar, myExpr,
createNameSuggestionGenerator(myExpr, propName, myProject, enteredName),
nameSuggestionGenerator,
createTypeSelectorManager(occurences, initializerType), methodToSearchFor, method, getParamsToRemove(method, occurences), mustBeFinal);
dialog.setReplaceAllOccurrences(replaceAllOccurrences);
dialog.setGenerateDelegate(delegate);
@@ -489,9 +505,9 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase {
myEditor.getSelectionModel().removeSelection();
}
};
SwingUtilities.invokeLater(cleanSelectionRunnable);
ApplicationManager.getApplication().invokeLater(cleanSelectionRunnable, ModalityState.any());
}
}
});
}
private TypeSelectorManagerImpl createTypeSelectorManager(PsiExpression[] occurences, PsiType initializerType) {
@@ -118,8 +118,7 @@ public class RootTypeConversionRule extends TypeConversionRule {
}
final PsiType migrationType = methodTypeParamsSubstitutor.substitute(type);
if (!originalType.equals(migrationType) &&
!TypeConversionUtil.areTypesAssignmentCompatible(migrationType, actualParams[i])) {
if (!originalType.equals(migrationType) && !areParametersAssignable(migrationType, i, actualParams)) {
labeler.migrateExpressionType(actualParams[i], migrationType, context, false, true);
}
}
@@ -139,6 +138,19 @@ public class RootTypeConversionRule extends TypeConversionRule {
return null;
}
private static boolean areParametersAssignable(PsiType migrationType, int paramId, PsiExpression[] actualParams) {
if (migrationType instanceof PsiEllipsisType) {
for (int i = paramId; i < actualParams.length; i++) {
if (!TypeConversionUtil.areTypesAssignmentCompatible(migrationType, actualParams[i])) {
return false;
}
}
return true;
} else {
return TypeConversionUtil.areTypesAssignmentCompatible(migrationType, actualParams[paramId]);
}
}
private static class MyStaticMethodConversionDescriptor extends TypeConversionDescriptorBase {
private final @NotNull String myTargetClassQName;
@@ -100,14 +100,21 @@ public class JavaGenericsUtil {
}
PsiMethod psiMethod = (PsiMethod)resolve;
if (!psiMethod.isVarArgs()) {
PsiParameter[] parameters = psiMethod.getParameterList().getParameters();
int parametersCount = parameters.length;
if (parametersCount == 0) {
return false;
}
PsiParameter varargParameter = parameters[parametersCount - 1];
if (!varargParameter.isVarArgs()) {
return false;
}
if (AnnotationUtil.isAnnotated(psiMethod, "java.lang.SafeVarargs", false, false)) {
return false;
}
int parametersCount = psiMethod.getParameterList().getParametersCount();
PsiParameter varargParameter = psiMethod.getParameterList().getParameters()[parametersCount - 1];
PsiType componentType = ((PsiEllipsisType)varargParameter.getType()).getComponentType();
if (isReifiableType(resolveResult.getSubstitutor().substitute(componentType))) {
return false;
@@ -0,0 +1,8 @@
import java.util.ArrayList;
class Test {
<T> ArrayList<T> foo () {
return new ArrayList<>();
}
}
@@ -0,0 +1,8 @@
import java.util.ArrayList;
class Test {
<T> ArrayList<T> foo () {
return new Arr<caret>
}
}
@@ -0,0 +1,12 @@
import java.util.function.Consumer;
class Test {
private static <T> void _f(Consumer<T> c) {}
private static void bar(final String s) {}
public static void main(String[] argArr) {
Test.<String>_f(Test::bar);
}
}
@@ -0,0 +1,12 @@
import java.util.function.Consumer;
class Test {
private static <T> void _f(Consumer<T> c) {}
private static void bar(final String s) {}
public static void main(String[] argArr) {
Test.<String>_f(b<caret>);
}
}
@@ -18,6 +18,10 @@ class P2 {
});
test(this::<warning descr="Method annotated with @Nullable must not override @NotNull method">getNull</warning>);
test(this::getPrimitive);
test(this::<warning descr="Not annotated method is used as an override for a method annotated with NotNull">getNonAnnotated</warning>);
test(WithImplicitConstructor::new);
test(WithExplicitConstructor::new);
}
@Nullable
@@ -29,3 +33,6 @@ class P2 {
private void test(final NonnullInterface function) { }
}
class WithImplicitConstructor {}
class WithExplicitConstructor { WithExplicitConstructor() {} }
@@ -42,6 +42,10 @@ public class SmartType17CompletionTest extends LightFixtureCompletionTestCase {
doTest();
}
public void testDiamondCollapsedWithMethodTypeParameter() throws Exception {
doTest();
}
public void testDiamondNotCollapsed() throws Exception {
doTest();
}
@@ -156,6 +156,10 @@ public class SmartType18CompletionTest extends LightFixtureCompletionTestCase {
}
public void testStaticMethodReference() { doTest(false); }
public void testStaticMethodReferenceInContextWithTypeArgs() {
configureByTestName();
checkResultByFile("/" + getTestName(false) + "-out.java");
}
public void testOuterMethodReference() { doTest(true); }
public void testNoAnonymousOuterMethodReference() { doAntiTest(); }
@@ -862,6 +862,10 @@ public class TypeMigrationTest extends TypeMigrationTestBase {
doTestMethodType("migrationMethod", PsiType.VOID);
}
public void testGenericEllipsis() {
doTestFieldType("migrationField", myJavaFacade.getElementFactory().createTypeFromText("Test<Short>", null));
}
private void doTestReturnType(final String methodName, final String migrationType) {
start(new RulesProvider() {
@Override
@@ -0,0 +1,10 @@
Types:
PsiField:migrationField : Test<java.lang.Short>
PsiMethodCallExpression:migrationField.method() : void
PsiReferenceExpression:migrationField : Test<java.lang.Short>
Conversions:
migrationField.method() -> $
New expression type changes:
Fails:
@@ -0,0 +1,11 @@
class Test<X> {
private static Test<Short> migrationField;
private static void m() {
migrationField.method();
}
void method(X... xes) {
}
}
@@ -0,0 +1,11 @@
class Test<X> {
private static Test<Integer> migrationField;
private static void m() {
migrationField.method();
}
void method(X... xes) {
}
}
+22 -22
View File
@@ -119,28 +119,28 @@ public class _JsonLexer implements FlexLexer {
/* The ZZ_CMAP_A table has 920 entries */
static final char ZZ_CMAP_A[] = zzUnpackCMap(
"\11\20\1\3\1\2\2\1\1\2\6\20\4\0\1\3\1\20\1\7\1\0\1\20\2\0\1\11\2\20\1\6\1"+
"\17\1\25\1\12\1\15\1\4\1\13\11\14\1\26\5\0\5\20\1\16\5\20\1\23\1\10\1\24\1"+
"\0\1\20\1\0\1\34\3\20\1\32\1\33\5\20\1\35\1\20\1\37\3\20\1\30\1\36\1\27\1"+
"\31\5\20\1\21\1\0\1\22\7\20\1\5\2\20\1\3\1\0\4\20\4\0\1\20\2\0\1\20\7\0\1"+
"\20\4\0\1\20\5\0\7\20\1\0\2\20\4\0\4\20\16\0\5\20\7\0\1\20\1\0\1\20\1\0\5"+
"\20\1\0\2\20\2\0\4\20\10\0\1\20\1\0\3\20\1\0\1\20\1\0\4\20\1\0\13\20\1\0\1"+
"\20\2\0\6\20\1\0\7\20\1\0\1\20\15\0\1\20\1\0\2\20\1\0\2\20\1\0\4\20\10\0\1"+
"\20\4\0\4\20\1\0\4\20\1\0\13\20\2\0\4\20\2\0\11\20\6\0\10\20\2\0\2\20\1\0"+
"\3\20\1\0\4\20\2\0\6\20\1\0\1\20\3\0\4\20\2\0\5\20\2\0\4\20\5\0\2\20\1\0\4"+
"\20\4\0\2\20\1\0\2\20\1\0\2\20\1\0\2\20\2\0\1\20\1\0\3\20\2\0\3\20\3\0\4\20"+
"\1\0\1\20\7\0\3\20\1\0\2\20\1\0\5\20\1\0\3\20\2\0\1\20\11\0\2\20\1\0\6\20"+
"\3\0\3\20\1\0\4\20\3\0\2\20\1\0\1\20\1\0\2\20\3\0\2\20\3\0\1\20\6\0\3\20\3"+
"\0\3\20\5\0\2\20\2\0\2\20\5\0\1\20\1\0\5\20\1\0\4\20\1\0\1\20\4\0\1\20\4\0"+
"\6\20\1\0\1\20\3\0\2\20\5\0\2\20\1\0\1\20\2\0\2\20\1\0\1\20\2\0\1\20\3\0\3"+
"\20\1\0\1\20\1\0\1\20\5\0\1\20\1\0\1\20\1\0\1\20\4\0\5\20\1\0\4\20\1\3\10"+
"\20\1\0\2\20\4\0\4\20\3\0\1\20\3\0\3\20\5\0\5\20\1\0\1\20\1\0\1\20\1\0\1\20"+
"\1\0\1\20\2\0\3\20\1\0\2\20\13\3\5\20\2\1\5\20\1\3\4\0\1\20\12\0\1\3\1\0\1"+
"\20\3\0\3\20\1\0\5\20\2\0\1\20\1\0\4\20\1\0\1\20\5\0\5\20\4\0\1\20\1\0\1\3"+
"\4\0\3\20\1\0\2\20\2\0\3\20\2\0\5\20\2\0\6\20\1\0\3\20\1\0\2\20\2\0\2\20\1"+
"\0\2\20\1\0\2\20\2\0\3\20\3\0\2\20\3\0\2\20\2\0\3\20\4\0\3\20\1\0\2\20\1\0"+
"\2\20\3\0\1\20\2\0\5\20\1\0\2\20\1\0\3\20\2\0\1\20\4\0\1\20\2\0\2\20\2\0\4"+
"\20\1\0\4\20\1\0\1\20\1\0\5\20\1\0\4\20\2\0\1\20\1\0\1\20\5\0\1\20\1\0\1\20"+
"\1\0\3\20");
"\17\1\25\1\12\1\15\1\4\1\13\11\14\1\26\1\0\3\20\1\0\5\20\1\16\5\20\1\23\1"+
"\10\1\24\2\20\1\0\1\34\3\20\1\32\1\33\5\20\1\35\1\20\1\37\3\20\1\30\1\36\1"+
"\27\1\31\5\20\1\21\1\0\1\22\7\20\1\5\2\20\1\3\1\0\4\20\4\0\1\20\2\0\1\20\7"+
"\0\1\20\4\0\1\20\5\0\7\20\1\0\2\20\4\0\4\20\16\0\5\20\7\0\1\20\1\0\1\20\1"+
"\0\5\20\1\0\2\20\2\0\4\20\10\0\1\20\1\0\3\20\1\0\1\20\1\0\4\20\1\0\13\20\1"+
"\0\1\20\2\0\6\20\1\0\7\20\1\0\1\20\15\0\1\20\1\0\2\20\1\0\2\20\1\0\4\20\10"+
"\0\1\20\4\0\4\20\1\0\4\20\1\0\13\20\2\0\4\20\2\0\11\20\6\0\10\20\2\0\2\20"+
"\1\0\3\20\1\0\4\20\2\0\6\20\1\0\1\20\3\0\4\20\2\0\5\20\2\0\4\20\5\0\2\20\1"+
"\0\4\20\4\0\2\20\1\0\2\20\1\0\2\20\1\0\2\20\2\0\1\20\1\0\3\20\2\0\3\20\3\0"+
"\4\20\1\0\1\20\7\0\3\20\1\0\2\20\1\0\5\20\1\0\3\20\2\0\1\20\11\0\2\20\1\0"+
"\6\20\3\0\3\20\1\0\4\20\3\0\2\20\1\0\1\20\1\0\2\20\3\0\2\20\3\0\1\20\6\0\3"+
"\20\3\0\3\20\5\0\2\20\2\0\2\20\5\0\1\20\1\0\5\20\1\0\4\20\1\0\1\20\4\0\1\20"+
"\4\0\6\20\1\0\1\20\3\0\2\20\5\0\2\20\1\0\1\20\2\0\2\20\1\0\1\20\2\0\1\20\3"+
"\0\3\20\1\0\1\20\1\0\1\20\5\0\1\20\1\0\1\20\1\0\1\20\4\0\5\20\1\0\4\20\1\3"+
"\10\20\1\0\2\20\4\0\4\20\3\0\1\20\3\0\3\20\5\0\5\20\1\0\1\20\1\0\1\20\1\0"+
"\1\20\1\0\1\20\2\0\3\20\1\0\2\20\13\3\5\20\2\1\5\20\1\3\4\0\1\20\12\0\1\3"+
"\1\0\1\20\3\0\3\20\1\0\5\20\2\0\1\20\1\0\4\20\1\0\1\20\5\0\5\20\4\0\1\20\1"+
"\0\1\3\4\0\3\20\1\0\2\20\2\0\3\20\2\0\5\20\2\0\6\20\1\0\3\20\1\0\2\20\2\0"+
"\2\20\1\0\2\20\1\0\2\20\2\0\3\20\3\0\2\20\3\0\2\20\2\0\3\20\4\0\3\20\1\0\2"+
"\20\1\0\2\20\3\0\1\20\2\0\5\20\1\0\2\20\1\0\3\20\2\0\1\20\4\0\1\20\2\0\2\20"+
"\2\0\4\20\1\0\4\20\1\0\1\20\1\0\5\20\1\0\4\20\2\0\1\20\1\0\1\20\5\0\1\20\1"+
"\0\1\20\1\0\3\20");
/**
* Translates DFA states to action switch labels.
+3 -2
View File
@@ -43,9 +43,10 @@
// auto completion of keywords. Semantically, it represents "bad word" type
// of tokens
// Could be as loose as [^\s\[\]{}:,\"\']+, but is slightly more restricted
// for the time being to match most forms of npm package names in package.json.
// for the time being to match most forms of npm package names and semver versions
// in package.json.
// See https://github.com/npm/validate-npm-package-name
IDENTIFIER="regexp:[[:jletterdigit:]~!()*\-./@]+"
IDENTIFIER="regexp:[[:jletterdigit:]~!()*\-./@\^<>=]+"
]
extends("container|literal|reference_expression")=value
+1 -1
View File
@@ -30,7 +30,7 @@ BLOCK_COMMENT="/"\*([^*]|\*+[^*/])*(\*+"/")?
DOUBLE_QUOTED_STRING=\"([^\\\"\r\n]|\\[^\r\n])*\"?
SINGLE_QUOTED_STRING='([^\\'\r\n]|\\[^\r\n])*'?
NUMBER=-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]*)?
IDENTIFIER=[[:jletterdigit:]~!()*\-."/"@]+
IDENTIFIER=[[:jletterdigit:]~!()*\-."/"@\^<>=]+
%%
<YYINITIAL> {
@@ -1,5 +1,9 @@
{
<weak_warning descr="JSON standard does not allow comments. Use JSMin or similar tool to remove comments before parsing.">/* Property key checks */</weak_warning>
"dependencies": {
<error descr="JSON standard does not allow such tokens">@foo/bar</error>: <error descr="JSON standard does not allow such tokens">^0.1</error>,
<error descr="JSON standard does not allow such tokens">foo.bar</error>: <error descr="JSON standard does not allow such tokens">=1.2</error>
},
"key1": null,
<error descr="JSON standard allows only double quoted string as property key"><error descr="JSON standard does not allow single quoted strings">'key2'</error></error>: null,
<error descr="JSON standard does not allow such tokens">key3</error>: null,
@@ -10,7 +14,7 @@
"key5": <error descr="JSON standard does not allow single quoted strings">'foo'</error>,
"key6": <error descr="JSON standard does not allow such tokens">foo</error>,
"key7": [42<error descr="JSON standard does not allow trailing comma">,</error>],
"key8": false<error descr="JSON standard does not allow trailing comma">,</error>
"key8": false<error descr="JSON standard does not allow trailing comma">,</error>
}
<error descr="JSON standard allows only one top-level value">["another", "top-level", "value"]</error>
<error descr="JSON standard allows only one top-level value">null</error>
@@ -1,5 +1,11 @@
{
"devDependencies": {
@types/3d-bin.packing: 42
@types/3d-bin.packing: 42,
"pkg1": ^4.15.0,
"pkg2": ~4.15.0,
"pkg3": >4.15.0,
"pkg4": >=4.15.0,
"pkg5": <4.15.0,
"pkg6": <=4.15.0
}
}
@@ -17,6 +17,60 @@ JsonFile: ExtendedIdentifierToken.json
PsiWhiteSpace(' ')
JsonNumberLiteral
PsiElement(NUMBER)('42')
PsiElement(,)(',')
PsiWhiteSpace('\n ')
JsonProperty
JsonStringLiteral
PsiElement(DOUBLE_QUOTED_STRING)('"pkg1"')
PsiElement(:)(':')
PsiWhiteSpace(' ')
JsonReferenceExpression
PsiElement(IDENTIFIER)('^4.15.0')
PsiElement(,)(',')
PsiWhiteSpace('\n ')
JsonProperty
JsonStringLiteral
PsiElement(DOUBLE_QUOTED_STRING)('"pkg2"')
PsiElement(:)(':')
PsiWhiteSpace(' ')
JsonReferenceExpression
PsiElement(IDENTIFIER)('~4.15.0')
PsiElement(,)(',')
PsiWhiteSpace('\n ')
JsonProperty
JsonStringLiteral
PsiElement(DOUBLE_QUOTED_STRING)('"pkg3"')
PsiElement(:)(':')
PsiWhiteSpace(' ')
JsonReferenceExpression
PsiElement(IDENTIFIER)('>4.15.0')
PsiElement(,)(',')
PsiWhiteSpace('\n ')
JsonProperty
JsonStringLiteral
PsiElement(DOUBLE_QUOTED_STRING)('"pkg4"')
PsiElement(:)(':')
PsiWhiteSpace(' ')
JsonReferenceExpression
PsiElement(IDENTIFIER)('>=4.15.0')
PsiElement(,)(',')
PsiWhiteSpace('\n ')
JsonProperty
JsonStringLiteral
PsiElement(DOUBLE_QUOTED_STRING)('"pkg5"')
PsiElement(:)(':')
PsiWhiteSpace(' ')
JsonReferenceExpression
PsiElement(IDENTIFIER)('<4.15.0')
PsiElement(,)(',')
PsiWhiteSpace('\n ')
JsonProperty
JsonStringLiteral
PsiElement(DOUBLE_QUOTED_STRING)('"pkg6"')
PsiElement(:)(':')
PsiWhiteSpace(' ')
JsonReferenceExpression
PsiElement(IDENTIFIER)('<=4.15.0')
PsiWhiteSpace('\n ')
PsiElement(})('}')
PsiWhiteSpace('\n')
@@ -27,6 +27,7 @@ import com.intellij.packaging.artifacts.ModifiableArtifactModel;
import com.intellij.packaging.elements.PackagingElementResolvingContext;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Vladislav.Soroka
@@ -71,4 +72,7 @@ public interface IdeModifiableModelsProvider extends IdeModelsProvider {
void dispose();
void setTestModuleProperties(Module testModule, String productionModuleName);
@Nullable
String getProductionModuleName(Module module);
}
@@ -46,6 +46,8 @@ public interface ImportSpec {
boolean isPreviewMode();
boolean shouldCreateDirectoriesForEmptyContentRoots();
boolean isReportRefreshError();
@Nullable
@@ -43,6 +43,7 @@ public class ImportSpecBuilder {
@Nullable private String myVmOptions;
@Nullable private String myArguments;
private boolean myUseDefaultCallback;
private boolean myCreateDirectoriesForEmptyContentRoots;
public ImportSpecBuilder(@NotNull Project project, @NotNull ProjectSystemId id) {
myProject = project;
@@ -50,6 +51,11 @@ public class ImportSpecBuilder {
myProgressExecutionMode = ProgressExecutionMode.IN_BACKGROUND_ASYNC;
}
public ImportSpecBuilder(ImportSpec importSpec) {
this(importSpec.getProject(), importSpec.getExternalSystemId());
apply(importSpec);
}
public ImportSpecBuilder whenAutoImportEnabled() {
myWhenAutoImportEnabled = true;
return this;
@@ -79,6 +85,11 @@ public class ImportSpecBuilder {
return this;
}
public ImportSpecBuilder createDirectoriesForEmptyContentRoots() {
myCreateDirectoriesForEmptyContentRoots = true;
return this;
}
public ImportSpecBuilder dontReportRefreshErrors() {
isReportRefreshError = false;
return this;
@@ -104,6 +115,7 @@ public class ImportSpecBuilder {
mySpec.setWhenAutoImportEnabled(myWhenAutoImportEnabled);
mySpec.setProgressExecutionMode(myProgressExecutionMode);
mySpec.setForceWhenUptodate(myForceWhenUptodate);
mySpec.setCreateDirectoriesForEmptyContentRoots(myCreateDirectoriesForEmptyContentRoots);
if (myUseDefaultCallback) {
mySpec.setCallback(new ExternalProjectRefreshCallback() {
@Override
@@ -129,4 +141,16 @@ public class ImportSpecBuilder {
mySpec.setVmOptions(myVmOptions);
return mySpec;
}
private void apply(ImportSpec spec) {
myWhenAutoImportEnabled = spec.whenAutoImportEnabled();
myProgressExecutionMode = spec.getProgressExecutionMode();
myForceWhenUptodate = spec.isForceWhenUptodate();
myCreateDirectoriesForEmptyContentRoots = spec.shouldCreateDirectoriesForEmptyContentRoots();
myCallback = spec.getCallback();
isPreviewMode = spec.isPreviewMode();
isReportRefreshError = spec.isReportRefreshError();
myArguments = spec.getArguments();
myVmOptions = spec.getVmOptions();
}
}
@@ -34,6 +34,7 @@ public class ImportSpecImpl implements ImportSpec {
private boolean whenAutoImportEnabled;
@Nullable private ExternalProjectRefreshCallback myCallback;
private boolean isPreviewMode;
private boolean createDirectoriesForEmptyContentRoots;
private boolean isReportRefreshError;
@Nullable private String myVmOptions;
@Nullable private String myArguments;
@@ -103,6 +104,15 @@ public class ImportSpecImpl implements ImportSpec {
this.isPreviewMode = isPreviewMode;
}
@Override
public boolean shouldCreateDirectoriesForEmptyContentRoots() {
return createDirectoriesForEmptyContentRoots;
}
public void setCreateDirectoriesForEmptyContentRoots(boolean createDirectoriesForEmptyContentRoots) {
this.createDirectoriesForEmptyContentRoots = createDirectoriesForEmptyContentRoots;
}
@Override
public boolean isReportRefreshError() {
return isReportRefreshError;
@@ -52,7 +52,8 @@ public class ExternalSystemStartupActivity implements StartupActivity {
for (ExternalSystemManager manager : ExternalSystemManager.EP_NAME.getExtensions()) {
final boolean isNewProject = project.getUserData(ExternalSystemDataKeys.NEWLY_CREATED_PROJECT) == Boolean.TRUE;
if (isNewProject) {
ExternalSystemUtil.refreshProjects(new ImportSpecBuilder(project, manager.getSystemId()));
ExternalSystemUtil.refreshProjects(new ImportSpecBuilder(project, manager.getSystemId())
.createDirectoriesForEmptyContentRoots());
}
}
}
@@ -433,4 +433,10 @@ public abstract class AbstractIdeModifiableModelsProvider extends IdeModelsProvi
public void setTestModuleProperties(Module testModule, String productionModuleName) {
myProductionModulesForTestModules.put(testModule, productionModuleName);
}
@Nullable
@Override
public String getProductionModuleName(Module module) {
return myProductionModulesForTestModules.get(module);
}
}
@@ -15,11 +15,11 @@
*/
package com.intellij.openapi.externalSystem.service.project.manage;
import com.intellij.ide.projectView.ProjectView;
import com.intellij.ide.projectView.impl.ProjectViewPane;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.Key;
import com.intellij.openapi.externalSystem.model.ProjectKeys;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.*;
import com.intellij.openapi.externalSystem.model.project.ContentRootData;
import com.intellij.openapi.externalSystem.model.project.ContentRootData.SourceRoot;
import com.intellij.openapi.externalSystem.model.project.ExternalSystemSourceType;
@@ -30,6 +30,7 @@ import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettin
import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.externalSystem.util.ExternalSystemConstants;
import com.intellij.openapi.externalSystem.util.ExternalSystemUtil;
import com.intellij.openapi.externalSystem.util.Order;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
@@ -64,6 +65,8 @@ import java.util.Set;
*/
@Order(ExternalSystemConstants.BUILTIN_SERVICE_ORDER)
public class ContentRootDataService extends AbstractProjectDataService<ContentRootData, ContentEntry> {
public static final com.intellij.openapi.util.Key<Boolean> CREATE_EMPTY_DIRECTORIES =
com.intellij.openapi.util.Key.create("createEmptyDirectories");
private static final Logger LOG = Logger.getInstance("#" + ContentRootDataService.class.getName());
@@ -82,6 +85,14 @@ public class ContentRootDataService extends AbstractProjectDataService<ContentRo
return;
}
boolean isNewlyImportedProject = project.getUserData(ExternalSystemDataKeys.NEWLY_IMPORTED_PROJECT) == Boolean.TRUE;
boolean forceDirectoriesCreation = false;
DataNode<ProjectData> projectDataNode = ExternalSystemApiUtil.findParent(toImport.iterator().next(), ProjectKeys.PROJECT);
if (projectDataNode != null) {
forceDirectoriesCreation = projectDataNode.getUserData(CREATE_EMPTY_DIRECTORIES) == Boolean.TRUE;
}
Set<Module> modulesToExpand = ContainerUtil.newTroveSet();
MultiMap<DataNode<ModuleData>, DataNode<ContentRootData>> byModule = ExternalSystemApiUtil.groupBy(toImport, ModuleData.class);
for (Map.Entry<DataNode<ModuleData>, Collection<DataNode<ContentRootData>>> entry : byModule.entrySet()) {
Module module = entry.getKey().getUserData(AbstractModuleDataService.MODULE_KEY);
@@ -93,13 +104,34 @@ public class ContentRootDataService extends AbstractProjectDataService<ContentRo
));
continue;
}
importData(modelsProvider, entry.getValue(), module);
importData(modelsProvider, entry.getValue(), module, forceDirectoriesCreation);
if (forceDirectoriesCreation ||
(isNewlyImportedProject &&
projectData != null &&
projectData.getLinkedExternalProjectPath().equals(ExternalSystemApiUtil.getExternalProjectPath(module)))) {
modulesToExpand.add(module);
}
}
if (!modulesToExpand.isEmpty()) {
for (Module module : modulesToExpand) {
String productionModuleName = modelsProvider.getProductionModuleName(module);
if (productionModuleName == null || !modulesToExpand.contains(modelsProvider.findIdeModule(productionModuleName))) {
VirtualFile[] roots = modelsProvider.getModifiableRootModel(module).getContentRoots();
if (roots.length > 0) {
VirtualFile virtualFile = roots[0];
ExternalSystemUtil.invokeLater(project, ModalityState.NON_MODAL, () -> {
final ProjectView projectView = ProjectView.getInstance(project);
projectView.changeViewCB(ProjectViewPane.ID, null).doWhenProcessed(() -> projectView.selectCB(null, virtualFile, false));
});
}
}
}
}
}
private static void importData(@NotNull IdeModifiableModelsProvider modelsProvider,
@NotNull final Collection<DataNode<ContentRootData>> data,
@NotNull final Module module) {
@NotNull final Module module, boolean forceDirectoriesCreation) {
final ModifiableRootModel modifiableRootModel = modelsProvider.getModifiableRootModel(module);
final ContentEntry[] contentEntries = modifiableRootModel.getContentEntries();
final Map<String, ContentEntry> contentEntriesMap = ContainerUtilRt.newHashMap();
@@ -107,8 +139,8 @@ public class ContentRootDataService extends AbstractProjectDataService<ContentRo
contentEntriesMap.put(contentEntry.getUrl(), contentEntry);
}
boolean createEmptyContentRootDirectories = false;
if (!data.isEmpty()) {
boolean createEmptyContentRootDirectories = forceDirectoriesCreation;
if (!forceDirectoriesCreation && !data.isEmpty()) {
ProjectSystemId projectSystemId = data.iterator().next().getData().getOwner();
AbstractExternalSystemSettings externalSystemSettings =
ExternalSystemApiUtil.getSettings(module.getProject(), projectSystemId);
@@ -438,21 +438,21 @@ public class ExternalProjectsDataStorage implements SettingsSavingComponent, Per
@Property(surroundWithTag = false)
@MapAnnotation(surroundWithTag = false, surroundValueWithTag = false, surroundKeyWithTag = false,
keyAttributeName = "path", entryTagName = "projectState")
public Map<String, ProjectState> map = ContainerUtil.newConcurrentMap();
public final Map<String, ProjectState> map = ContainerUtil.newConcurrentMap();
}
static class ProjectState {
@Property(surroundWithTag = false)
@MapAnnotation(surroundWithTag = false, surroundValueWithTag = false, surroundKeyWithTag = false,
keyAttributeName = "path", entryTagName = "dataType")
public Map<String, ModuleState> map = ContainerUtil.newConcurrentMap();
public final Map<String, ModuleState> map = ContainerUtil.newConcurrentMap();
public boolean isInclusion;
}
static class ModuleState {
@Property(surroundWithTag = false)
@AbstractCollection(surroundWithTag = false, elementTag = "id")
public Set<String> set = ContainerUtil.newConcurrentSet();
public final Set<String> set = ContainerUtil.newConcurrentSet();
public ModuleState() {
}
@@ -101,7 +101,13 @@ public abstract class AbstractExternalProjectSettingsControl<S extends ExternalP
if (!myCustomizer.isUseAutoImportBoxHidden() && myUseAutoImportBox != null) {
myUseAutoImportBox.setSelected(getInitialSettings().isUseAutoImport());
}
if (!myCustomizer.isCreateEmptyContentRootDirectoriesBoxHidden() && myCreateEmptyContentRootDirectoriesBox != null) {
if(isDefaultModuleCreation) {
if(myCreateEmptyContentRootDirectoriesBox != null) {
myCreateEmptyContentRootDirectoriesBox.getParent().remove(myCreateEmptyContentRootDirectoriesBox);
myCreateEmptyContentRootDirectoriesBox = null;
}
}
if (!isDefaultModuleCreation && !myCustomizer.isCreateEmptyContentRootDirectoriesBoxHidden() && myCreateEmptyContentRootDirectoriesBox != null) {
myCreateEmptyContentRootDirectoriesBox.setSelected(getInitialSettings().isCreateEmptyContentRootDirectories());
}
resetExtraSettings(isDefaultModuleCreation);
@@ -35,7 +35,6 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.externalSystem.ExternalSystemManager;
import com.intellij.openapi.externalSystem.importing.ImportSpec;
import com.intellij.openapi.externalSystem.importing.ImportSpecImpl;
import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder;
import com.intellij.openapi.externalSystem.model.*;
import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings;
@@ -52,6 +51,7 @@ import com.intellij.openapi.externalSystem.service.internal.ExternalSystemResolv
import com.intellij.openapi.externalSystem.service.notification.ExternalSystemNotificationManager;
import com.intellij.openapi.externalSystem.service.notification.NotificationSource;
import com.intellij.openapi.externalSystem.service.project.ExternalProjectRefreshCallback;
import com.intellij.openapi.externalSystem.service.project.manage.ContentRootDataService;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
@@ -238,7 +238,7 @@ public class ExternalSystemUtil {
/**
* Asks to refresh all external projects of the target external system linked to the given ide project based on provided spec
*
* @param specBuilder import specification builder
* @param spec import specification
*/
public static void refreshProjects(@NotNull final ImportSpec spec) {
ExternalSystemManager<?, ?, ?, ?, ?> manager = ExternalSystemApiUtil.getManager(spec.getExternalSystemId());
@@ -273,8 +273,7 @@ public class ExternalSystemUtil {
.clearNotifications(null, NotificationSource.PROJECT_SYNC, spec.getExternalSystemId());
for (String path : toRefresh) {
refreshProject(
spec.getProject(), spec.getExternalSystemId(), path, callback, false, spec.getProgressExecutionMode());
refreshProject(path, new ImportSpecBuilder(spec).callback(callback).build());
}
}
}
@@ -394,7 +393,9 @@ public class ExternalSystemUtil {
ExternalSystemProcessingManager processingManager = ServiceManager.getService(ExternalSystemProcessingManager.class);
if (processingManager.findTask(ExternalSystemTaskType.RESOLVE_PROJECT, externalSystemId, externalProjectPath) != null) {
callback.onFailure(ExternalSystemBundle.message("error.resolve.already.running", externalProjectPath), null);
if (callback != null) {
callback.onFailure(ExternalSystemBundle.message("error.resolve.already.running", externalProjectPath), null);
}
return;
}
@@ -413,7 +414,13 @@ public class ExternalSystemUtil {
final Throwable error = myTask.getError();
if (error == null) {
callback.onSuccess(myTask.getExternalProject());
if (callback != null) {
DataNode<ProjectData> externalProject = myTask.getExternalProject();
if (externalProject != null && importSpec.shouldCreateDirectoriesForEmptyContentRoots()) {
externalProject.putUserData(ContentRootDataService.CREATE_EMPTY_DIRECTORIES, Boolean.TRUE);
}
callback.onSuccess(externalProject);
}
if (!isPreviewMode) {
externalSystemTaskActivator.runTasks(externalProjectPath, ExternalSystemTaskActivator.Phase.AFTER_SYNC);
}
@@ -430,7 +437,9 @@ public class ExternalSystemUtil {
);
}
callback.onFailure(message, extractDetails(error));
if (callback != null) {
callback.onFailure(message, extractDetails(error));
}
ExternalSystemManager<?, ?, ?, ?, ?> manager = ExternalSystemApiUtil.getManager(externalSystemId);
if (manager == null) {
@@ -278,7 +278,7 @@ public abstract class AbstractLayoutCodeProcessor {
return new FileTreeIterator(myProject);
}
return new FileTreeIterator(Collections.<PsiFile>emptyList());
return new FileTreeIterator(Collections.emptyList());
}
@NotNull
@@ -355,7 +355,7 @@ public abstract class AbstractLayoutCodeProcessor {
LOG.error(e);
}
};
runLayoutCodeProcess(readAction, writeAction, false );
runLayoutCodeProcess(readAction, writeAction);
}
private boolean checkFileWritable(final PsiFile file){
@@ -396,7 +396,7 @@ public abstract class AbstractLayoutCodeProcessor {
return !GeneratedSourcesFilter.isGeneratedSourceByAnyFilter(virtualFile, file.getProject());
}
private void runLayoutCodeProcess(final Runnable readAction, final Runnable writeAction, final boolean globalAction) {
private void runLayoutCodeProcess(final Runnable readAction, final Runnable writeAction) {
final ProgressWindow progressWindow = new ProgressWindow(true, myProject);
progressWindow.setTitle(myCommandName);
progressWindow.setText(myProgressText);
@@ -418,7 +418,6 @@ public abstract class AbstractLayoutCodeProcessor {
}
final Runnable writeRunnable = () -> CommandProcessor.getInstance().executeCommand(myProject, () -> {
if (globalAction) CommandProcessor.getInstance().markCurrentCommandAsGlobal(myProject);
try {
writeAction.run();
@@ -544,18 +543,15 @@ public abstract class AbstractLayoutCodeProcessor {
}
private void performFileProcessing(@NotNull PsiFile file) {
myProcessors.stream().forEach((processor) -> {
Ref<FutureTask<Boolean>> writeTaskRef = Ref.create();
ApplicationManager.getApplication().runReadAction(() -> writeTaskRef.set(processor.prepareTask(file, myProcessChangedTextOnly)));
for (AbstractLayoutCodeProcessor processor : myProcessors) {
FutureTask<Boolean> writeTask = ReadAction.compute(() -> processor.prepareTask(file, myProcessChangedTextOnly));
ProgressIndicatorProvider.checkCanceled();
FutureTask<Boolean> writeTask = writeTaskRef.get();
ApplicationManager.getApplication().invokeAndWait(() -> WriteCommandAction.runWriteCommandAction(myProject, myCommandName, null, writeTask));
checkStop(writeTask, file);
});
}
}
private void checkStop(FutureTask<Boolean> task, PsiFile file) {
@@ -565,6 +561,11 @@ public abstract class AbstractLayoutCodeProcessor {
}
}
catch (InterruptedException | ExecutionException e) {
Throwable cause = e.getCause();
if (cause instanceof IndexNotReadyException) {
LOG.warn(cause);
return;
}
LOG.error("Got unexpected exception during formatting " + file, e);
}
}
@@ -25,13 +25,8 @@ import com.intellij.ide.GeneralSettings;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -75,12 +70,11 @@ public class TerminateRemoteProcessDialog {
};
AtomicBoolean alreadyGone = new AtomicBoolean(false);
Window projectWindow = WindowManager.getInstance().suggestParentWindow(project);
Runnable dialogRemover = Messages.createMessageDialogRemover(project);
ProcessAdapter listener = new ProcessAdapter() {
public void processWillTerminate(ProcessEvent event, boolean willBeDestroyed) {
alreadyGone.set(true);
UIUtil.invokeLaterIfNeeded(() -> makeCurrentMessageDialogGoAway(
projectWindow != null ? projectWindow.getOwnedWindows() : Window.getWindows()));
dialogRemover.run();
}
};
processHandler.addProcessListener(listener);
@@ -101,17 +95,6 @@ public class TerminateRemoteProcessDialog {
return getConfirmation(exitCode, canDisconnect);
}
private static void makeCurrentMessageDialogGoAway(@NotNull Window[] checkWindows) {
for (Window w : checkWindows) {
JDialog dialog = w instanceof JDialog ? (JDialog)w : null;
if (dialog == null || !dialog.isModal()) continue;
JButton cancelButton = UIUtil.uiTraverser(dialog.getRootPane()).filter(JButton.class)
.filter(b -> CommonBundle.getCancelButtonText().equals(b.getText()))
.first();
if (cancelButton != null) cancelButton.doClick();
}
}
private static GeneralSettings.ProcessCloseConfirmation getConfirmation(int button, boolean withDisconnect) {
switch (button) {
case 0:
@@ -531,7 +531,7 @@ public abstract class HierarchyBrowserBaseEx extends HierarchyBrowserBase implem
changeView(currentViewType);
final HierarchyTreeBuilder builder = getCurrentBuilder();
builder.restoreExpandedAndSelectedInfo(storedInfo.get());
}, __->!myAlarm.isDisposed());
}, __-> isDisposed());
}
protected String getCurrentScopeType() {
@@ -36,8 +36,10 @@ public class AnsiEscapeDecoder {
private static final String M_CSI = "m" + CSI;
private static final char BACKSPACE = '\b';
private Key myCurrentTextAttributes;
private final ColoredOutputTypeRegistry myColoredOutputTypeRegistry = ColoredOutputTypeRegistry.getInstance();
private Key myCurrentTextAttributes;
private String myUnhandledStdout;
private String myUnhandledStderr;
/**
* Parses ansi-color codes from text and sends text fragments with color attributes to textAcceptor
@@ -48,31 +50,40 @@ public class AnsiEscapeDecoder {
* It can implement ColoredChunksAcceptor to receive list of pairs (text, attribute).
*/
public void escapeText(@NotNull String text, @NotNull Key outputType, @NotNull ColoredTextAcceptor textAcceptor) {
text = prependUnhandledText(text, outputType);
text = normalizeAsciiControlCharacters(text);
int pos = 0;
List<Pair<String, Key>> chunks = null;
int unhandledSuffixLength = 0;
while (true) {
int escSeqBeginInd = text.indexOf(CSI, pos);
int escSeqBeginInd = findEscSeqBeginIndex(text, pos);
if (escSeqBeginInd < 0) {
if (escSeqBeginInd < -1) {
unhandledSuffixLength = decodeUnhandledSuffixLength(escSeqBeginInd);
}
break;
}
if (pos < escSeqBeginInd) {
chunks = processTextChunk(chunks, text.substring(pos, escSeqBeginInd), outputType, textAcceptor);
}
final int escSeqEndInd = findEscSeqEndIndex(text, escSeqBeginInd);
int escSeqEndInd = findConsecutiveEscSequencesEndIndex(text, escSeqBeginInd);
if (escSeqEndInd < 0) {
if (escSeqEndInd < -1) {
unhandledSuffixLength = decodeUnhandledSuffixLength(escSeqEndInd);
}
break;
}
if (text.charAt(escSeqEndInd - 1) == 'm') {
String escSeq = text.substring(escSeqBeginInd, escSeqEndInd);
if (text.charAt(escSeqEndInd) == 'm') {
String escSeq = text.substring(escSeqBeginInd, escSeqEndInd + 1);
// this is a simple fix for RUBY-8996:
// we replace several consecutive escape sequences with one which contains all these sequences
String colorAttribute = StringUtil.replace(escSeq, M_CSI, ";");
myCurrentTextAttributes = myColoredOutputTypeRegistry.getOutputKey(colorAttribute);
}
pos = escSeqEndInd;
pos = escSeqEndInd + 1;
}
if (pos < text.length()) {
updateUnhandledSuffix(text, outputType, unhandledSuffixLength);
if (unhandledSuffixLength == 0 && pos < text.length()) {
chunks = processTextChunk(chunks, text.substring(pos), outputType, textAcceptor);
}
if (chunks != null && textAcceptor instanceof ColoredChunksAcceptor) {
@@ -80,6 +91,30 @@ public class AnsiEscapeDecoder {
}
}
private void updateUnhandledSuffix(@NotNull String text, @NotNull Key outputType, int unhandledSuffixLength) {
String unhandledSuffix = unhandledSuffixLength > 0 ? text.substring(text.length() - unhandledSuffixLength) : null;
if (outputType == ProcessOutputTypes.STDOUT) {
myUnhandledStdout = unhandledSuffix;
}
else if (outputType == ProcessOutputTypes.STDERR) {
myUnhandledStderr = unhandledSuffix;
}
}
@NotNull
private String prependUnhandledText(@NotNull String text, @NotNull Key outputType) {
String prevUnhandledText = null;
if (outputType == ProcessOutputTypes.STDOUT) {
prevUnhandledText = myUnhandledStdout;
myUnhandledStdout = null;
}
else if (outputType == ProcessOutputTypes.STDERR) {
prevUnhandledText = myUnhandledStderr;
myUnhandledStderr = null;
}
return prevUnhandledText != null ? prevUnhandledText + text : text;
}
@NotNull
private static String normalizeAsciiControlCharacters(@NotNull String text) {
int ind = text.indexOf(BACKSPACE);
@@ -122,29 +157,58 @@ public class AnsiEscapeDecoder {
return result.toString();
}
/*
* Selects all consecutive escape sequences and returns escape sequence end index (exclusive).
* If the escape sequence isn't finished, returns -1.
/**
* Returns the index of the first occurrence of CSI within the passed string that is greater than or equal to {@code fromIndex},
* or negative number if CSI is not found: -1 - (length of text suffix to keep in case of an incomplete CSI).
*/
private static int findEscSeqEndIndex(@NotNull String text, final int escSeqBeginInd) {
int beginInd = escSeqBeginInd;
while (true) {
int letterInd = findEscSeqLetterIndex(text, beginInd);
if (letterInd == -1) {
return beginInd == escSeqBeginInd ? -1 : beginInd;
}
if (text.charAt(letterInd) != 'm') {
return beginInd == escSeqBeginInd ? letterInd + 1 : beginInd;
}
beginInd = letterInd + 1;
}
}
private static int findEscSeqLetterIndex(@NotNull String text, int escSeqBeginInd) {
if (!text.regionMatches(escSeqBeginInd, CSI, 0, CSI.length())) {
private static int findEscSeqBeginIndex(@NotNull String text, int fromIndex) {
int ind = text.indexOf(CSI.charAt(0), fromIndex);
if (ind == -1) {
return -1;
}
int parameterEndInd = escSeqBeginInd + 2;
else if (ind == text.length() - 1) {
return encodeUnhandledSuffixLength(text, ind);
}
return text.charAt(ind + 1) == CSI.charAt(1) ? ind : -1;
}
/**
* Returns end index of all consecutive escape sequences started at {@code firstEscSeqBeginInd}, or
* negative number if not found: -1 - (length of string suffix to keep in case of an incomplete last escape sequence).
*/
private static int findConsecutiveEscSequencesEndIndex(@NotNull String text, int firstEscSeqBeginInd) {
int escSeqBeginInd = firstEscSeqBeginInd;
int lastMatchedColorEscSeqEndInd = -1;
int escSeqEndInd;
while ((escSeqEndInd = findEscSeqEndIndex(text, escSeqBeginInd)) >= 0) {
if (text.charAt(escSeqEndInd) != 'm') {
// Handle non-color escape sequences separately
// ColoredOutputTypeRegistry expects only color escape sequences and in a single consecutive text chunk
return lastMatchedColorEscSeqEndInd > 0 ? lastMatchedColorEscSeqEndInd : escSeqEndInd;
}
escSeqBeginInd = escSeqEndInd + 1;
lastMatchedColorEscSeqEndInd = escSeqEndInd;
if (escSeqEndInd + 1 >= text.length()) {
return encodeUnhandledSuffixLength(text, firstEscSeqBeginInd);
}
if (text.charAt(escSeqEndInd + 1) != CSI.charAt(0)) {
break;
}
if (escSeqEndInd + 2 >= text.length()) {
return encodeUnhandledSuffixLength(text, firstEscSeqBeginInd);
}
if (text.charAt(escSeqEndInd + 2) != CSI.charAt(1)) {
break;
}
}
if (escSeqEndInd < -1) {
return encodeUnhandledSuffixLength(text, firstEscSeqBeginInd);
}
return lastMatchedColorEscSeqEndInd;
}
private static int findEscSeqEndIndex(@NotNull String text, int escSeqBeginInd) {
int parameterEndInd = escSeqBeginInd + CSI.length();
while (parameterEndInd < text.length()) {
char ch = text.charAt(parameterEndInd);
if (Character.isDigit(ch) || ch == ';') {
@@ -154,13 +218,21 @@ public class AnsiEscapeDecoder {
break;
}
}
if (parameterEndInd < text.length()) {
char letter = text.charAt(parameterEndInd);
if (StringUtil.containsChar("ABCDEFGHJKSTfmisu", letter)) {
return parameterEndInd;
}
if (parameterEndInd == text.length()) {
return encodeUnhandledSuffixLength(text, escSeqBeginInd);
}
return -1;
return StringUtil.containsChar("ABCDEFGHJKSTfmisu", text.charAt(parameterEndInd)) ? parameterEndInd : -1;
}
private static int encodeUnhandledSuffixLength(@NotNull String text, int suffixStartInd) {
return -1 - (text.length() - suffixStartInd);
}
private static int decodeUnhandledSuffixLength(int encodedUnhandledSuffixLength) {
if (encodedUnhandledSuffixLength >= -1) {
throw new AssertionError();
}
return -encodedUnhandledSuffixLength - 1;
}
@Nullable
@@ -26,6 +26,7 @@ import com.intellij.pom.Navigatable;
import com.intellij.psi.PsiElement;
import com.intellij.psi.SmartPointerManager;
import com.intellij.psi.SmartPsiElementPointer;
import com.intellij.util.ObjectUtils;
import org.jetbrains.annotations.NotNull;
import static com.intellij.openapi.util.Conditions.or;
@@ -39,8 +40,9 @@ public class PsiElementNavigatable implements Navigatable {
@Override
public final void navigate(boolean requestFocus) {
PsiElement element = myPointer.getElement();
if (element != null && element.isValid()) {
PsiElement originalElement = myPointer.getElement();
if (originalElement != null && originalElement.isValid()) {
PsiElement element = ObjectUtils.notNull(originalElement.getNavigationElement(), originalElement);
VirtualFile file = element.getContainingFile().getVirtualFile();
if (file != null) {
new Task.Modal(element.getProject(), EditorBundle.message("editor.open.file.progress", file.getName()), true) {
@@ -62,7 +64,7 @@ public class PsiElementNavigatable implements Navigatable {
@Override
public boolean canNavigate() {
PsiElement element = myPointer.getElement();
return element != null && element.isValid() && element.getContainingFile().getVirtualFile() != null;
return element != null && element.isValid() && ObjectUtils.notNull(element.getNavigationElement(), element).getContainingFile().getVirtualFile() != null;
}
@Override
@@ -112,6 +112,24 @@ public class Messages {
return UIUtil.getQuestionIcon();
}
@NotNull
public static Runnable createMessageDialogRemover(@Nullable Project project) {
Window projectWindow = project == null ? null : WindowManager.getInstance().suggestParentWindow(project);
return () -> UIUtil.invokeLaterIfNeeded(() -> makeCurrentMessageDialogGoAway(
projectWindow != null ? projectWindow.getOwnedWindows() : Window.getWindows()));
}
private static void makeCurrentMessageDialogGoAway(@NotNull Window[] checkWindows) {
for (Window w : checkWindows) {
JDialog dialog = w instanceof JDialog ? (JDialog)w : null;
if (dialog == null || !dialog.isModal()) continue;
JButton cancelButton = UIUtil.uiTraverser(dialog.getRootPane()).filter(JButton.class)
.filter(b -> CommonBundle.getCancelButtonText().equals(b.getText()))
.first();
if (cancelButton != null) cancelButton.doClick();
}
}
/**
* Please, use {@link #showOkCancelDialog} or {@link #showYesNoCancelDialog} if possible (these dialogs implements native OS behavior)!
* @return number of button pressed: from 0 up to options.length-1 inclusive, or -1 for Cancel
@@ -19,10 +19,10 @@ import com.intellij.internal.statistic.beans.ConvertUsagesUtil;
import com.intellij.internal.statistic.beans.GroupDescriptor;
import com.intellij.internal.statistic.beans.UsageDescriptor;
import com.intellij.openapi.components.*;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.xmlb.annotations.MapAnnotation;
import com.intellij.util.xmlb.annotations.Tag;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
@@ -42,11 +42,11 @@ public class UsageTrigger implements PersistentStateComponent<UsageTrigger.State
private State myState = new State();
public static void trigger(@NotNull String feature) {
public static void trigger(@NotNull @NonNls String feature) {
getInstance().doTrigger(feature);
}
public static void triggerOnce(@NotNull String feature) {
public static void triggerOnce(@NotNull @NonNls String feature) {
if (!getInstance().myState.myValues.containsKey(feature)) {
getInstance().doTrigger(feature);
}
@@ -397,7 +397,7 @@ public final class ActionMenu extends JBMenu {
ComponentEvent componentEvent = (ComponentEvent)event;
Component component = componentEvent.getComponent();
JPopupMenu popup = UIUtil.getParentOfType(JPopupMenu.class, component);
if (popup != null && popup.getInvoker() == myComponent) {
if (popup != null && popup.getInvoker() == myComponent && popup.isShowing()) {
Rectangle bounds = popup.getBounds();
if (bounds.isEmpty()) return;
bounds.setLocation(popup.getLocationOnScreen());
@@ -860,12 +860,40 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
};
if (hasUnsafeBgTasks || option.isToBeShown()) {
AtomicBoolean alreadyGone = new AtomicBoolean(false);
if (hasUnsafeBgTasks) {
Runnable dialogRemover = Messages.createMessageDialogRemover(null);
Runnable task = new Runnable() {
@Override
public void run() {
if (alreadyGone.get()) return;
if (!ProgressManager.getInstance().hasUnsafeProgressIndicator()) {
alreadyGone.set(true);
dialogRemover.run();
}
else {
JobScheduler.getScheduler().schedule(this, 1, TimeUnit.SECONDS);
}
}
};
JobScheduler.getScheduler().schedule(task, 1, TimeUnit.SECONDS);
}
String name = ApplicationNamesInfo.getInstance().getFullProductName();
String message = ApplicationBundle.message(hasUnsafeBgTasks ? "exit.confirm.prompt.tasks" : "exit.confirm.prompt", name);
int result = MessageDialogBuilder.yesNo(ApplicationBundle.message("exit.confirm.title"), message)
.yesText(ApplicationBundle.message("command.exit"))
.noText(CommonBundle.message("button.cancel"))
.doNotAsk(option).show();
if (alreadyGone.getAndSet(true)) {
if (!option.isToBeShown()) {
return true;
}
result = MessageDialogBuilder.yesNo(ApplicationBundle.message("exit.confirm.title"),
ApplicationBundle.message("exit.confirm.prompt", name))
.yesText(ApplicationBundle.message("command.exit"))
.noText(CommonBundle.message("button.cancel"))
.doNotAsk(option).show();
}
if (result != Messages.YES) {
return false;
}
@@ -1,8 +1,6 @@
package com.intellij.execution.process;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.BufferExposingByteArrayInputStream;
import com.intellij.testFramework.PlatformTestCase;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.util.Consumer;
@@ -10,101 +8,138 @@ import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.junit.Assert;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Collection;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
public class AnsiEscapeDecoderTest extends PlatformTestCase {
private static final String STDOUT_KEY = ProcessOutputTypes.STDOUT.toString();
private static final String STDERR_KEY = ProcessOutputTypes.STDERR.toString();
public void testTextWithoutColors() throws Exception {
AnsiEscapeDecoder decoder = new AnsiEscapeDecoder();
decoder.escapeText("", ProcessOutputTypes.STDOUT, createExpectedAcceptor(
Pair.create("", ProcessOutputTypes.STDOUT)
));
decoder.escapeText("simple text", ProcessOutputTypes.STDOUT, createExpectedAcceptor(
Pair.create("simple text", ProcessOutputTypes.STDOUT)
));
check(new ColoredText(""));
check(new ColoredText("simple text").addExpected("simple text", STDOUT_KEY));
}
public void testSingleColoredChunk() throws Exception {
AnsiEscapeDecoder decoder = new AnsiEscapeDecoder();
decoder.escapeText("Chrome 35.0.1916 (Linux): Executed 0 of 1\u001B[32m SUCCESS\u001B[39m (0 secs / 0 secs)\n", ProcessOutputTypes.STDOUT, createExpectedAcceptor(
Pair.create("Chrome 35.0.1916 (Linux): Executed 0 of 1", ProcessOutputTypes.STDOUT),
Pair.create(" SUCCESS", ColoredOutputTypeRegistry.getInstance().getOutputKey("\u001B[32m")),
Pair.create(" (0 secs / 0 secs)\n", ColoredOutputTypeRegistry.getInstance().getOutputKey("\u001B[39m"))
));
check(new ColoredText("Chrome 35.0.1916 (Linux): Executed 0 of 1\u001B[32m SUCCESS\u001B[39m (0 secs / 0 secs)\n")
.addExpected("Chrome 35.0.1916 (Linux): Executed 0 of 1", STDOUT_KEY)
.addExpected(" SUCCESS", "\u001B[32m")
.addExpected(" (0 secs / 0 secs)\n", "\u001B[39m"));
}
public void testCompoundEscSeq() throws Exception {
AnsiEscapeDecoder decoder = new AnsiEscapeDecoder();
decoder.escapeText("E\u001B[41m\u001B[37mE\u001B[0mE", ProcessOutputTypes.STDOUT, createExpectedAcceptor(
Pair.create("E", ProcessOutputTypes.STDOUT),
Pair.create("E", ColoredOutputTypeRegistry.getInstance().getOutputKey("\u001B[41;37m")),
Pair.create("E", ProcessOutputTypes.STDOUT)
));
check(new ColoredText("E\u001B[41m\u001B[37mE\u001B[0mE")
.addExpected("E", STDOUT_KEY)
.addExpected("E", "\u001B[41;37m")
.addExpected("E", STDOUT_KEY));
}
public void testOtherEscSeq() throws Exception {
AnsiEscapeDecoder decoder = new AnsiEscapeDecoder();
decoder.escapeText("Plain\u001B[32mGreen\u001B[39mNormal\u001B[1A\u001B[2K\u001B[31mRed\u001B[39m",
ProcessOutputTypes.STDOUT,
createExpectedAcceptor(
Pair.create("Plain", ProcessOutputTypes.STDOUT),
Pair.create("Green", ColoredOutputTypeRegistry.getInstance().getOutputKey("\u001B[32m")),
Pair.create("Normal", ColoredOutputTypeRegistry.getInstance().getOutputKey("\u001B[39m")),
Pair.create("Red", ColoredOutputTypeRegistry.getInstance().getOutputKey("\u001B[31m"))
)
);
check(new ColoredText("Plain\u001B[32mGreen\u001B[39mNormal\u001B[1A\u001B[2K\u001B[31mRed\u001B[39m")
.addExpected("Plain", STDOUT_KEY)
.addExpected("Green", "\u001B[32m")
.addExpected("Normal", "\u001B[39m")
.addExpected("Red", "\u001B[31m"));
}
public void testBackspaceControlSequence() throws Exception {
check(false, ContainerUtil.newArrayList(
new ColoredText(" 10% 0/1 build modules\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b 70% 1/1 build modules")
.addExpected(" 70% 1/1 build modules", STDOUT_KEY),
new ColoredText(
"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b 40% 1/2 build modules\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b 30% 1/3 build modules\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b 25% 1/4 build modules")
.addExpected("\n 25% 1/4 build modules", STDOUT_KEY)
));
}
public void testIncompleteEscapeSequences() throws Exception {
check(true, ContainerUtil.newArrayList(
new ColoredText("\u001B"),
new ColoredText("[33m Hello\u001B[3").addExpected(" Hello", "\u001B[33m"),
new ColoredText("4m, Work!").addExpected(", Work!", "\u001B[34m")
));
check(true, ContainerUtil.newArrayList(
new ColoredText("\u001B[1;33m<\u001B[34mnamespace\u001B[1")
.addExpected("<", "\u001B[1;33m")
.addExpected("namespace", "\u001B[34m"),
new ColoredText(
";33m:abcd\u001B[0m\u001B[1;33m>\u001B[0m0\u001B[1;33m</\u001B[34mnamespace\u001B[1;33m:abcd\u001B[0m\u001B[1;33m>\u001B[0m")
.addExpected(":abcd", "\u001B[1;33m")
.addExpected(">", "\u001B[0;1;33m")
.addExpected("0", "stdout")
.addExpected("</", "\u001B[1;33m")
.addExpected("namespace", "\u001B[34m")
.addExpected(":abcd", "\u001B[1;33m")
.addExpected(">", "\u001B[0;1;33m")
));
}
private static void check(@NotNull ColoredText text) {
check(true, Collections.singletonList(text));
}
private static void check(boolean testCharByCharProcessing, @NotNull List<ColoredText> texts) {
AnsiEscapeDecoder decoder = new AnsiEscapeDecoder();
decoder.escapeText(" 10% 0/1 build modules\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b 70% 1/1 build modules",
ProcessOutputTypes.STDERR,
createExpectedAcceptor(
Pair.create(" 70% 1/1 build modules", ProcessOutputTypes.STDERR)
)
);
decoder.escapeText("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b 40% 1/2 build modules\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b 30% 1/3 build modules\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b 25% 1/4 build modules",
ProcessOutputTypes.STDERR,
createExpectedAcceptor(
Pair.create("\n 25% 1/4 build modules", ProcessOutputTypes.STDERR)
)
);
}
@NotNull
private static List<Pair<String, String>> toListWithKeyName(@NotNull Collection<Pair<String, Key>> list) {
return ContainerUtil.map(list, pair -> Pair.create(pair.first, pair.second.toString()));
}
@SafeVarargs
private static AnsiEscapeDecoder.ColoredChunksAcceptor createExpectedAcceptor(@NotNull final Pair<String, Key>... expected) {
return new AnsiEscapeDecoder.ColoredChunksAcceptor() {
@Override
public void coloredChunksAvailable(@NotNull List<Pair<String, Key>> chunks) {
List<Pair<String, String>> expectedWithKeyName = toListWithKeyName(Arrays.asList(expected));
List<Pair<String, String>> actualWithKeyName = toListWithKeyName(chunks);
Assert.assertEquals(expectedWithKeyName, actualWithKeyName);
}
@Override
public void coloredTextAvailable(@NotNull String text, @NotNull Key attributes) {
throw new RuntimeException(); // shouldn't be called
}
List<Pair<String, String>> actualColoredChunks = ContainerUtil.newArrayList();
//noinspection CodeBlock2Expr
AnsiEscapeDecoder.ColoredTextAcceptor acceptor = (text, attributes) -> {
actualColoredChunks.add(Pair.create(text, attributes.toString()));
};
// test stdout
for (ColoredText text : texts) {
decoder.escapeText(text.myRawText, ProcessOutputTypes.STDOUT, acceptor);
}
List<Pair<String, String>> expectedColoredChunks = new ArrayList<>();
for (ColoredText text : texts) {
expectedColoredChunks.addAll(text.myExpectedColoredChunks);
}
Assert.assertEquals(expectedColoredChunks, actualColoredChunks);
if (testCharByCharProcessing) {
// test stdout char by char
actualColoredChunks.clear();
decoder = new AnsiEscapeDecoder();
for (ColoredText text : texts) {
for (int i = 0; i < text.myRawText.length(); i++) {
decoder.escapeText(String.valueOf(text.myRawText.charAt(i)), ProcessOutputTypes.STDOUT, acceptor);
}
}
expectedColoredChunks.clear();
for (ColoredText text : texts) {
for (Pair<String, String> chunk : text.myExpectedColoredChunks) {
String chunkText = chunk.first;
for (int i = 0; i < chunkText.length(); i++) {
expectedColoredChunks.add(Pair.create(String.valueOf(chunkText.charAt(i)), chunk.second));
}
}
}
Assert.assertEquals(expectedColoredChunks, actualColoredChunks);
}
// test stderr
actualColoredChunks.clear();
decoder = new AnsiEscapeDecoder();
for (ColoredText text : texts) {
decoder.escapeText(text.myRawText, ProcessOutputTypes.STDERR, acceptor);
}
expectedColoredChunks.clear();
for (ColoredText text : texts) {
for (Pair<String, String> chunk : text.myExpectedColoredChunks) {
expectedColoredChunks.add(Pair.create(chunk.first, STDERR_KEY));
}
}
Assert.assertEquals(expectedColoredChunks, actualColoredChunks);
}
@NotNull
public static Process createTestProcess() {
// have to be synchronised because used from pooled thread
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(10000);
BufferExposingByteArrayInputStream inputStream = new BufferExposingByteArrayInputStream(new byte[0]);
AtomicBoolean finished = new AtomicBoolean();
return new Process() {
@Override
@@ -114,17 +149,17 @@ public class AnsiEscapeDecoderTest extends PlatformTestCase {
@Override
public InputStream getInputStream() {
return inputStream;
return new ByteArrayInputStream(new byte[0]);
}
@Override
public InputStream getErrorStream() {
return inputStream;
return new ByteArrayInputStream(new byte[0]);
}
@Override
public int waitFor() {
while (!finished.get());
while (!finished.get()) {}
return 0;
}
@@ -143,11 +178,14 @@ public class AnsiEscapeDecoderTest extends PlatformTestCase {
public void testPerformance() throws IOException {
Process testProcess = createTestProcess();
//noinspection CodeBlock2Expr
withProcessHandlerFrom(testProcess, handler -> {
PlatformTestUtil.startPerformanceTest("ansi color", 15000, ()->{
for (int i=0; i<2_000_000;i++) {
handler.notifyTextAvailable(i+"Chrome 35.0.1916 (Linux): Executed 0 of 1\u001B[32m SUCCESS\u001B[39m (0 secs / 0 secs)\n", ProcessOutputTypes.STDOUT);
handler.notifyTextAvailable(i+"Plain\u001B[32mGreen\u001B[39mNormal\u001B[1A\u001B[2K\u001B[31mRed\u001B[39m\n", ProcessOutputTypes.SYSTEM);
PlatformTestUtil.startPerformanceTest("ansi color", 15000, () -> {
for (int i = 0; i < 2_000_000; i++) {
handler.notifyTextAvailable(i + "Chrome 35.0.1916 (Linux): Executed 0 of 1\u001B[32m SUCCESS\u001B[39m (0 secs / 0 secs)\n",
ProcessOutputTypes.STDOUT);
handler.notifyTextAvailable(i + "Plain\u001B[32mGreen\u001B[39mNormal\u001B[1A\u001B[2K\u001B[31mRed\u001B[39m\n",
ProcessOutputTypes.SYSTEM);
}
}).cpuBound().assertTiming();
});
@@ -168,4 +206,18 @@ public class AnsiEscapeDecoderTest extends PlatformTestCase {
handler.waitFor();
}
}
private static class ColoredText {
private final String myRawText;
private final List<Pair<String, String>> myExpectedColoredChunks = new ArrayList<>();
public ColoredText(@NotNull String rawText) {
myRawText = rawText;
}
private ColoredText addExpected(@NotNull String text, @NotNull String colorKey) {
myExpectedColoredChunks.add(Pair.create(text, colorKey));
return this;
}
}
}
@@ -50,52 +50,53 @@ abstract class RemoteVmConnection : VmConnection<Vm>() {
port = address.port
setState(ConnectionStatus.WAITING_FOR_CONNECTION, "Connecting to ${address.hostString}:${address.port}")
val result = AsyncPromise<Vm>()
var attemptNumber = 0
fun attempt() {
connectCancelHandler.set { result.setError("Closed explicitly") }
val connectionPromise = AsyncPromise<Any?>()
connectionPromise.rejected { result.setError(it) }
result
.done {
vm = it!!
setState(ConnectionStatus.CONNECTED, "Connected to ${connectedAddressToPresentation(address, it)}")
startProcessing()
}
.rejected {
if (it !is ConnectException) {
LOG.errorIfNotMessage(it)
}
setState(ConnectionStatus.CONNECTION_FAILED, it.message)
}
.processed { connectCancelHandler.set(null) }
createBootstrap(address, result)
.connect(address, connectionPromise,
maxAttemptCount = if (stopCondition == null) NettyUtil.DEFAULT_CONNECT_ATTEMPT_COUNT else -1,
stopCondition = stopCondition)
?.closeFuture()?.addListener {
if (result.isFulfilled) {
close("Process disconnected unexpectedly", ConnectionStatus.DISCONNECTED)
}
else {
if (++attemptNumber > 10 || (stopCondition?.value(null) ?: false)) {
result.setError("Cannot establish connection - promptly closed after open")
}
else {
sleep(result, 300)
attempt()
}
}
}
}
val future = ApplicationManager.getApplication().executeOnPooledThread {
if (Thread.interrupted()) {
return@executeOnPooledThread
}
var attemptNumber = 0
fun attempt() {
connectCancelHandler.set { result.setError("Closed explicitly") }
val connectionPromise = AsyncPromise<Any?>()
connectionPromise.rejected { result.setError(it) }
result
.done {
vm = it!!
setState(ConnectionStatus.CONNECTED, "Connected to ${connectedAddressToPresentation(address, it)}")
startProcessing()
}
.rejected {
if (it !is ConnectException) {
LOG.errorIfNotMessage(it)
}
setState(ConnectionStatus.CONNECTION_FAILED, it.message)
}
.processed { connectCancelHandler.set(null) }
createBootstrap(address, result)
.connect(address, connectionPromise,
maxAttemptCount = if (stopCondition == null) NettyUtil.DEFAULT_CONNECT_ATTEMPT_COUNT else -1,
stopCondition = stopCondition)
?.closeFuture()?.addListener {
if (result.isFulfilled) {
close("Process disconnected unexpectedly", ConnectionStatus.DISCONNECTED)
}
else {
if (++attemptNumber > 10 || (stopCondition?.value(null) ?: false)) {
result.setError("Process disconnected unexpectedly")
}
else {
sleep(result, 300)
attempt()
}
}
}
}
attempt()
}
@@ -29,7 +29,7 @@ import java.util.stream.LongStream;
/**
* @author peter
*/
class CpuTimings {
public class CpuTimings {
final long[] rawData;
long average;
private final double myStandardDeviation;
@@ -58,7 +58,7 @@ class CpuTimings {
@SuppressWarnings("UseOfSystemOutOrSystemErr")
static CpuTimings calcStableCpuTiming() {
for (int i = 0;; i++) {
CpuTimings timings = calcCpuTiming();
CpuTimings timings = calcCpuTiming(20, CpuTimings::addBigIntegers);
if (timings.myStandardDeviation < 1.8) {
return timings;
}
@@ -73,24 +73,47 @@ class CpuTimings {
}
}
private static CpuTimings calcCpuTiming() {
int n = 20;
long[] elapsed = new long[n];
for (int i = 0; i < n; i++) {
elapsed[i] = measureCPU();
private static CpuTimings calcCpuTiming(int iterationCount, Runnable oneIteration) {
long[] elapsed = new long[iterationCount];
for (int i = 0; i < iterationCount; i++) {
long start = System.currentTimeMillis();
oneIteration.run();
elapsed[i] = System.currentTimeMillis() - start;
}
return new CpuTimings(elapsed);
}
private static long measureCPU() {
long start = System.currentTimeMillis();
private static void addBigIntegers() {
BigInteger k = new BigInteger("1");
for (int i = 0; i < 1000000; i++) {
k = k.add(new BigInteger("1"));
}
}
return System.currentTimeMillis() - start;
private static void mulDiv() {
long k = 241;
for (int i = 0; i < 22_222_222; i++) {
k = i % 10 == 3 ? k * 239 : k % 12342;
}
ensureOdd(k);
}
private static void ensureOdd(long k) {
if (k % 2 == 0) {
throw new AssertionError("Should be an odd value");
}
}
private static void mulDivMemAccess() {
int[] array = new int[240_000];
for (int i = 0; i < array.length; i++) {
array[i] = i * 42 + 1;
}
int k = 241;
for (int i = 0; i < 5_750_000; i++) {
k *= array[Math.abs(k) % array.length];
}
ensureOdd(k);
}
public static double getProcessCpuLoad() {
@@ -134,4 +157,14 @@ class CpuTimings {
}
}
@SuppressWarnings("UseOfSystemOutOrSystemErr")
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
// each line can be uncommented alone, to check the results of different benchmarks
//System.out.println(calcCpuTiming(20, CpuTimings::addBigIntegers));
//System.out.println(calcCpuTiming(20, CpuTimings::mulDivMemAccess));
//System.out.println(calcCpuTiming(20, CpuTimings::mulDiv));
}
}
}
@@ -960,10 +960,12 @@ public class ArrayUtil extends ArrayUtilRt {
int n = time.length;
Arrays.sort(time);
long total = 0;
for (int i= n /2- n / part /2; i< n /2+ n / part /2; i++) {
int start = n / 2 - n / part / 2;
int end = n / 2 + n / part / 2;
for (int i = start; i < end; i++) {
total += time[i];
}
int middlePartLength = n / part;
int middlePartLength = end - start;
return middlePartLength == 0 ? 0 : total / middlePartLength;
}
@@ -972,10 +974,12 @@ public class ArrayUtil extends ArrayUtilRt {
int n = time.length;
Arrays.sort(time);
long total = 0;
for (int i= n /2- n / part /2; i< n /2+ n / part /2; i++) {
int start = n / 2 - n / part / 2;
int end = n / 2 + n / part / 2;
for (int i = start; i < end; i++) {
total += time[i];
}
int middlePartLength = n / part;
int middlePartLength = end - start;
return middlePartLength == 0 ? 0 : total / middlePartLength;
}
@@ -94,24 +94,26 @@ public class BeanBinding extends NotNullDeserializeBinding {
continue;
}
if (filter != null) {
if (filter instanceof SkipDefaultsSerializationFilter) {
if (((SkipDefaultsSerializationFilter)filter).equal(binding, o)) {
Property property = accessor.getAnnotation(Property.class);
if (property == null || !property.alwaysWrite()) {
if (filter != null) {
if (filter instanceof SkipDefaultsSerializationFilter) {
if (((SkipDefaultsSerializationFilter)filter).equal(binding, o)) {
continue;
}
}
else if (!filter.accepts(accessor, o)) {
continue;
}
}
else if (!filter.accepts(accessor, o)) {
//todo: optimize. Cache it.
if (property != null && property.filter() != SerializationFilter.class &&
!ReflectionUtil.newInstance(property.filter()).accepts(accessor, o)) {
continue;
}
}
//todo: optimize. Cache it.
Property property = accessor.getAnnotation(Property.class);
if (property != null && property.filter() != SerializationFilter.class &&
!ReflectionUtil.newInstance(property.filter()).accepts(accessor, o)) {
continue;
}
if (element == null) {
element = new Element(myTagName);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -31,4 +31,6 @@ public @interface Property {
boolean surroundWithTag() default true;
Class<? extends SerializationFilter> filter() default SerializationFilter.class;
boolean alwaysWrite() default false;
}
@@ -66,7 +66,7 @@ public class TestLocationDataRule implements GetDataRule {
if (fileIndex.isInContent(file) && !fileIndex.isInSource(file) && !fileIndex.isInLibraryClasses(file)) {
final VirtualFile parent = file.getParent();
final VirtualFile contentRoot = fileIndex.getContentRootForFile(file);
if (contentRoot != null) {
if (contentRoot != null && parent != null) {
final String relativePath = VfsUtilCore.getRelativePath(parent, contentRoot, '/');
if (relativePath != null) {
final PsiSearchHelper searchHelper = PsiSearchHelper.SERVICE.getInstance(project);
+1 -1
View File
@@ -136,7 +136,7 @@ public class PsiUtil {
return flag;
}
public static boolean isPluginProject(final Project project) {
public static boolean isPluginProject(@NotNull final Project project) {
return CachedValuesManager.getManager(project).getCachedValue(project, () -> {
boolean foundMarkerClass =
JavaPsiFacade.getInstance(project).findClass(IDE_PROJECT_MARKER_CLASS,
@@ -27,6 +27,8 @@ import com.intellij.ide.util.projectWizard.WizardContext;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.externalSystem.importing.ImportSpec;
import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder;
import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.model.project.ProjectId;
@@ -212,9 +214,12 @@ public class GradleModuleBuilder extends AbstractExternalModuleBuilder<GradlePro
settings.linkProject(gradleProjectSettings);
}
ExternalSystemUtil.refreshProject(
project, GradleConstants.SYSTEM_ID, rootProjectPath, false,
ProgressExecutionMode.IN_BACKGROUND_ASYNC);
ImportSpec importSpec = new ImportSpecBuilder(project, GradleConstants.SYSTEM_ID)
.use(ProgressExecutionMode.IN_BACKGROUND_ASYNC)
.createDirectoriesForEmptyContentRoots()
.useDefaultCallback()
.build();
ExternalSystemUtil.refreshProject(rootProjectPath, importSpec);
final PsiFile psiFile;
if (finalBuildScriptFile != null) {
@@ -47,6 +47,7 @@ import org.jetbrains.plugins.gradle.util.GradleUtil;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
@@ -496,6 +497,20 @@ public class IdeaGradleProjectSettingsControlBuilder implements GradleProjectSet
}
private void resetWrapperControls(String linkedProjectPath, @NotNull GradleProjectSettings settings, boolean isDefaultModuleCreation) {
if (isDefaultModuleCreation) {
JComponent[] toRemove = new JComponent[]{myUseWrapperWithVerificationButton, myUseWrapperVerificationLabel};
for (JComponent component : toRemove) {
if (component != null) {
Container parent = component.getParent();
if (parent != null) {
parent.remove(component);
}
}
}
myUseWrapperWithVerificationButton = null;
myUseWrapperVerificationLabel = null;
}
if (StringUtil.isEmpty(linkedProjectPath) && !isDefaultModuleCreation) {
if (myUseLocalDistributionButton != null) {
myUseLocalDistributionButton.setSelected(true);
+13 -10
View File
@@ -466,6 +466,7 @@ def console_exec(thread_id, frame_id, expression, dbg):
"""
frame = pydevd_vars.find_frame(thread_id, frame_id)
is_multiline = expression.count('@LINE@') > 1
expression = str(expression.replace('@LINE@', '\n'))
#Not using frame.f_globals because of https://sourceforge.net/tracker2/?func=detail&aid=2541355&group_id=85796&atid=577329
@@ -484,16 +485,18 @@ def console_exec(thread_id, frame_id, expression, dbg):
interpreter = ConsoleWriter()
try:
code = compile_command(expression)
except (OverflowError, SyntaxError, ValueError):
# Case 1
interpreter.showsyntaxerror()
return False
if code is None:
# Case 2
return True
if not is_multiline:
try:
code = compile_command(expression)
except (OverflowError, SyntaxError, ValueError):
# Case 1
interpreter.showsyntaxerror()
return False
if code is None:
# Case 2
return True
else:
code = expression
#Case 3
@@ -17,9 +17,12 @@ package com.jetbrains.python.actions;
import com.google.common.collect.Lists;
import com.intellij.execution.ExecutionHelper;
import com.intellij.execution.ExecutionManager;
import com.intellij.execution.console.LanguageConsoleView;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.ui.ExecutionConsole;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.execution.ui.RunContentManager;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.ex.util.EditorUtil;
@@ -27,15 +30,13 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentManager;
import com.intellij.util.Consumer;
import com.jetbrains.python.console.PyCodeExecutor;
import com.jetbrains.python.console.PydevConsoleRunner;
import com.jetbrains.python.console.PythonConsoleRunnerFactory;
import com.jetbrains.python.console.PythonConsoleToolWindow;
import com.jetbrains.python.console.*;
import com.jetbrains.python.psi.PyFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -176,11 +177,20 @@ public class PyExecuteSelectionAction extends AnAction {
ExecutionHelper
.selectContentDescriptor(dataContext, project, consoles, "Select console to execute in", descriptor -> {
if (descriptor != null && descriptor.getExecutionConsole() instanceof PyCodeExecutor) {
consumer.consume((PyCodeExecutor)descriptor.getExecutionConsole());
final PythonConsoleToolWindow toolWindow = PythonConsoleToolWindow.getInstance(project);
if (toolWindow != null && !toolWindow.getToolWindow().isVisible()) {
toolWindow.getToolWindow().show(null);
ContentManager contentManager = toolWindow.getToolWindow().getContentManager();
ExecutionConsole console = descriptor.getExecutionConsole();
consumer.consume((PyCodeExecutor)console);
ToolWindow toolWindow;
if (console instanceof PythonDebugLanguageConsoleView) {
RunContentManager runContentManager = ExecutionManager.getInstance(project).getContentManager();
toolWindow = runContentManager.getToolWindowByDescriptor(descriptor);
}
else {
PythonConsoleToolWindow consoleToolWindow = PythonConsoleToolWindow.getInstance(project);
toolWindow = consoleToolWindow != null ? consoleToolWindow.getToolWindow() : null;
}
if (toolWindow != null && !toolWindow.isVisible()) {
toolWindow.show(null);
ContentManager contentManager = toolWindow.getContentManager();
Content content = contentManager.findContent(descriptor.getDisplayName());
if (content != null) {
contentManager.setSelectedContent(content);
@@ -61,7 +61,7 @@ public class PythonDebugLanguageConsoleView extends DuplexConsoleView<ConsoleVie
@Override
public void executeCode(@NotNull String code, @Nullable Editor e) {
enableConsole(false);
getPydevConsoleView().executeCode(code, e);
getPydevConsoleView().executeInConsole(code);
}
@NotNull
@@ -312,6 +312,7 @@ public class WebBrowserManager extends SimpleModificationTracker implements Pers
public void setBrowserPath(@NotNull WebBrowser browser, @Nullable String path, boolean isActive) {
((ConfigurableWebBrowser)browser).setPath(path);
((ConfigurableWebBrowser)browser).setActive(isActive);
incModificationCount();
}
public WebBrowser addBrowser(final @NotNull UUID id,