diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpBraceMatcher.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpBraceMatcher.java index 748458d218d5..c815d4bc9c48 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpBraceMatcher.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpBraceMatcher.java @@ -30,6 +30,8 @@ public class RegExpBraceMatcher implements PairedBraceMatcher { new BracePair(RegExpTT.POS_LOOKBEHIND, RegExpTT.GROUP_END, true), new BracePair(RegExpTT.NEG_LOOKBEHIND, RegExpTT.GROUP_END, true), new BracePair(RegExpTT.PYTHON_NAMED_GROUP, RegExpTT.GROUP_END, true), new BracePair(RegExpTT.PYTHON_NAMED_GROUP_REF, RegExpTT.GROUP_END, true), + new BracePair(RegExpTT.RUBY_NAMED_GROUP, RegExpTT.GROUP_END, true), + new BracePair(RegExpTT.RUBY_QUOTED_NAMED_GROUP, RegExpTT.GROUP_END, true), new BracePair(RegExpTT.CLASS_BEGIN, RegExpTT.CLASS_END, false), new BracePair(RegExpTT.LBRACE, RegExpTT.RBRACE, false), new BracePair(RegExpTT.QUOTE_BEGIN, RegExpTT.QUOTE_END, false),}; } diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpHighlighter.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpHighlighter.java index fd3a8b03bd22..971cf56755fe 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpHighlighter.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpHighlighter.java @@ -120,6 +120,16 @@ public class RegExpHighlighter extends SyntaxHighlighterBase { keys1.put(RegExpTT.QUOTE_BEGIN, QUOTE_CHARACTER); keys1.put(RegExpTT.QUOTE_END, QUOTE_CHARACTER); + keys1.put(RegExpTT.NON_CAPT_GROUP, PARENTHS); + keys1.put(RegExpTT.POS_LOOKBEHIND, PARENTHS); + keys1.put(RegExpTT.NEG_LOOKBEHIND, PARENTHS); + keys1.put(RegExpTT.POS_LOOKAHEAD, PARENTHS); + keys1.put(RegExpTT.NEG_LOOKAHEAD, PARENTHS); + keys1.put(RegExpTT.SET_OPTIONS, PARENTHS); + keys1.put(RegExpTT.PYTHON_NAMED_GROUP, PARENTHS); + keys1.put(RegExpTT.PYTHON_NAMED_GROUP_REF, PARENTHS); + keys1.put(RegExpTT.RUBY_NAMED_GROUP, PARENTHS); + keys1.put(RegExpTT.RUBY_QUOTED_NAMED_GROUP, PARENTHS); keys1.put(RegExpTT.GROUP_BEGIN, PARENTHS); keys1.put(RegExpTT.GROUP_END, PARENTHS); diff --git a/RegExpSupport/src/org/intellij/lang/regexp/psi/RegExpGroup.java b/RegExpSupport/src/org/intellij/lang/regexp/psi/RegExpGroup.java index d1afd4e05b79..c0a1278b72dd 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/psi/RegExpGroup.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/psi/RegExpGroup.java @@ -29,6 +29,8 @@ public interface RegExpGroup extends RegExpAtom { boolean isRubyNamedGroup(); + boolean isNamedGroup(); + @Nullable String getGroupName(); } diff --git a/RegExpSupport/src/org/intellij/lang/regexp/psi/impl/RegExpGroupImpl.java b/RegExpSupport/src/org/intellij/lang/regexp/psi/impl/RegExpGroupImpl.java index b24669757917..023f64cf16b2 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/psi/impl/RegExpGroupImpl.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/psi/impl/RegExpGroupImpl.java @@ -56,6 +56,10 @@ public class RegExpGroupImpl extends RegExpElementImpl implements RegExpGroup { getNode().findChildByType(RegExpTT.RUBY_QUOTED_NAMED_GROUP) != null; } + public boolean isNamedGroup() { + return getNode().findChildByType(RegExpTT.RUBY_NAMED_GROUP) != null; + } + public String getGroupName() { if (!isPythonNamedGroup()) { return null; diff --git a/RegExpSupport/src/org/intellij/lang/regexp/validation/RegExpAnnotator.java b/RegExpSupport/src/org/intellij/lang/regexp/validation/RegExpAnnotator.java index 1d32bf8ab6eb..d326d2c28557 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/validation/RegExpAnnotator.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/validation/RegExpAnnotator.java @@ -124,14 +124,14 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot public void visitRegExpBackref(final RegExpBackref backref) { final RegExpGroup group = backref.resolve(); if (group == null) { - final Annotation a = myHolder.createErrorAnnotation(backref, "Unresolved backreference"); + final Annotation a = myHolder.createErrorAnnotation(backref, "Unresolved back reference"); if (a != null) { // IDEA-9381 a.setHighlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL); } } else if (PsiTreeUtil.isAncestor(group, backref, true)) { - myHolder.createWarningAnnotation(backref, "Backreference is nested into the capturing group it refers to"); + myHolder.createWarningAnnotation(backref, "Back reference is nested into the capturing group it refers to"); } } @@ -173,7 +173,7 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot */ final RegExpGroup group = groupRef.resolve(); if (group == null) { - final Annotation a = myHolder.createErrorAnnotation(groupRef, "Unresolved backreference"); + final Annotation a = myHolder.createErrorAnnotation(groupRef, "Unresolved back reference"); if (a != null) { // IDEA-9381 a.setHighlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL); diff --git a/RegExpSupport/testData/RETest.xml b/RegExpSupport/testData/RETest.xml index 3aac79ea8de6..0a8d963a861b 100644 --- a/RegExpSupport/testData/RETest.xml +++ b/RegExpSupport/testData/RETest.xml @@ -719,7 +719,7 @@ ERR - \1)]]> + \1)]]> OK diff --git a/build/update.xml b/build/update.xml index e06cfce3ee93..ae4871b2eb6b 100644 --- a/build/update.xml +++ b/build/update.xml @@ -31,6 +31,7 @@ + diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java index 48efa9ac87dc..cbeca23dd6f3 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java @@ -19,6 +19,7 @@ import com.intellij.debugger.SourcePosition; import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; @@ -80,8 +81,7 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler { //noinspection unchecked final List targets = new OrderedSet(); - TextRange textRange = element.getTextRange(); - final Range lines = new Range(doc.getLineNumber(textRange.getStartOffset()), doc.getLineNumber(textRange.getEndOffset())); + final Ref textRange = new Ref(lineRange); final PsiElementVisitor methodCollector = new JavaRecursiveElementVisitor() { final Stack myContextStack = new Stack(); @@ -96,12 +96,12 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler { @Override public void visitAnonymousClass(PsiAnonymousClass aClass) { for (PsiMethod psiMethod : aClass.getMethods()) { - targets.add(new MethodSmartStepTarget(psiMethod, getCurrentParamName(), psiMethod.getBody(), true, lines)); + targets.add(new MethodSmartStepTarget(psiMethod, getCurrentParamName(), psiMethod.getBody(), true, null)); } } public void visitLambdaExpression(PsiLambdaExpression expression) { - targets.add(new LambdaSmartStepTarget(expression, getCurrentParamName(), expression.getBody(), myNextLambdaExpressionOrdinal++, lines)); + targets.add(new LambdaSmartStepTarget(expression, getCurrentParamName(), expression.getBody(), myNextLambdaExpressionOrdinal++, null)); } @Override @@ -111,6 +111,15 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler { } } + @Override + public void visitExpression(PsiExpression expression) { + TextRange range = expression.getTextRange(); + if (lineRange.intersects(range)) { + textRange.set(textRange.get().union(range)); + } + super.visitExpression(expression); + } + public void visitExpressionList(PsiExpressionList expressionList) { final PsiMethod psiMethod = myContextStack.isEmpty()? null : myContextStack.peek(); if (psiMethod != null) { @@ -146,7 +155,7 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler { ((PsiMethodCallExpression)expression).getMethodExpression().getReferenceNameElement() : expression instanceof PsiNewExpression? ((PsiNewExpression)expression).getClassOrAnonymousClassReference() : expression, false, - lines + null )); } try { @@ -168,6 +177,11 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler { } sibling.accept(methodCollector); } + + Range lines = new Range(doc.getLineNumber(textRange.get().getStartOffset()), doc.getLineNumber(textRange.get().getEndOffset())); + for (SmartStepTarget target : targets) { + target.setCallingExpressionLines(lines); + } return targets; } return Collections.emptyList(); diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/SmartStepTarget.java b/java/debugger/impl/src/com/intellij/debugger/actions/SmartStepTarget.java index ed758c902784..a6579a94357c 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/SmartStepTarget.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/SmartStepTarget.java @@ -27,7 +27,7 @@ public abstract class SmartStepTarget { private final PsiElement myHighlightElement; private final String myLabel; private final boolean myNeedBreakpointRequest; - private final Range myExpressionLines; + private Range myExpressionLines; protected SmartStepTarget(@Nullable String label, @Nullable PsiElement highlightElement, boolean needBreakpointRequest, Range expressionLines) { myHighlightElement = highlightElement; @@ -53,4 +53,8 @@ public abstract class SmartStepTarget { public Range getCallingExpressionLines() { return myExpressionLines; } + + public void setCallingExpressionLines(Range expressionLines) { + myExpressionLines = expressionLines; + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/CompoundPositionManager.java b/java/debugger/impl/src/com/intellij/debugger/engine/CompoundPositionManager.java index 5ec84a8429f5..73d6f8bdb62b 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/CompoundPositionManager.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/CompoundPositionManager.java @@ -22,6 +22,7 @@ import com.intellij.debugger.engine.evaluation.EvaluationContext; import com.intellij.debugger.jdi.StackFrameProxyImpl; import com.intellij.debugger.requests.ClassPrepareRequestor; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ThreeState; import com.intellij.xdebugger.frame.XStackFrame; import com.sun.jdi.InternalException; @@ -101,9 +102,29 @@ public class CompoundPositionManager extends PositionManagerEx { return Collections.emptyList(); } + private static int mapToOriginalLine(int line, int[] mapping) { + for (int i = 0; i < mapping.length; i += 2) { + if (mapping[i + 1] == line) { + return mapping[i]; + } + } + return -1; + } + @Override @NotNull public List locationsOfLine(@NotNull ReferenceType type, @NotNull SourcePosition position) { + VirtualFile file = position.getFile().getVirtualFile(); + if (file != null) { + int[] data = file.getUserData(LINE_NUMBERS_MAPPING_KEY); + if (data != null) { + int line = mapToOriginalLine(position.getLine() + 1, data); + if (line > -1) { + position = SourcePosition.createFromLine(position.getFile(), line - 1); + } + } + } + for (PositionManager positionManager : myPositionManagers) { try { return positionManager.locationsOfLine(type, position); diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java index 44337a6f1ee3..c58e7770d449 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java @@ -140,7 +140,7 @@ public class PositionManagerImpl implements PositionManager { lineNumber = -1; } - if (psiFile instanceof PsiCompiledElement && lineNumber > -1) { + if (lineNumber > -1) { VirtualFile file = psiFile.getVirtualFile(); if (file != null) { int[] data = file.getUserData(LINE_NUMBERS_MAPPING_KEY); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointTypeBase.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointTypeBase.java index 7427f91df500..8f092e26975b 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointTypeBase.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointTypeBase.java @@ -15,6 +15,7 @@ */ package com.intellij.debugger.ui.breakpoints; +import com.intellij.debugger.PositionManager; import com.intellij.debugger.engine.DebuggerUtils; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; @@ -81,8 +82,8 @@ public abstract class JavaLineBreakpointTypeBase

myResults = ContainerUtil.newHashMap(); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/LiveVariablesAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/LiveVariablesAnalyzer.java index 55709d71ca49..937caa84e24d 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/LiveVariablesAnalyzer.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/LiveVariablesAnalyzer.java @@ -21,10 +21,11 @@ import com.intellij.codeInspection.dataFlow.value.DfaValueFactory; import com.intellij.codeInspection.dataFlow.value.DfaVariableValue; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.Pair; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiRecursiveElementWalkingVisitor; +import com.intellij.psi.PsiReferenceExpression; import com.intellij.util.PairFunction; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.FilteringIterator; -import com.intellij.util.containers.MultiMap; +import com.intellij.util.containers.*; import com.intellij.util.containers.Queue; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -39,6 +40,26 @@ public class LiveVariablesAnalyzer { private final Instruction[] myInstructions; private final MultiMap myForwardMap; private final MultiMap myBackwardMap; + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") private final FactoryMap> myClosureReads = new FactoryMap>() { + @Nullable + @Override + protected List create(PsiElement closure) { + final Set result = ContainerUtil.newLinkedHashSet(); + closure.accept(new PsiRecursiveElementWalkingVisitor() { + @Override + public void visitElement(PsiElement element) { + if (element instanceof PsiReferenceExpression) { + DfaValue value = myFactory.createValue((PsiReferenceExpression)element); + if (value instanceof DfaVariableValue) { + result.add((DfaVariableValue)value); + } + } + super.visitElement(element); + } + }); + return ContainerUtil.newArrayList(result); + } + }; public LiveVariablesAnalyzer(ControlFlow flow, DfaValueFactory factory) { myFactory = factory; @@ -96,12 +117,36 @@ public class LiveVariablesAnalyzer { return result; } + @Nullable + private static DfaVariableValue getWrittenVariable(Instruction instruction) { + if (instruction instanceof AssignInstruction) { + DfaValue value = ((AssignInstruction)instruction).getAssignedValue(); + return value instanceof DfaVariableValue ? (DfaVariableValue)value : null; + } + if (instruction instanceof FlushVariableInstruction) return ((FlushVariableInstruction)instruction).getVariable(); + return null; + } + + @NotNull + private List getReadVariables(Instruction instruction) { + if (instruction instanceof PushInstruction && !((PushInstruction)instruction).isReferenceWrite()) { + DfaValue value = ((PushInstruction)instruction).getValue(); + if (value instanceof DfaVariableValue) { + return Collections.singletonList((DfaVariableValue)value); + } + } else { + PsiElement closure = DfaUtil.getClosureInside(instruction); + if (closure != null) { + return myClosureReads.get(closure); + } + } + return Collections.emptyList(); + } + private boolean isInterestingInstruction(Instruction instruction) { if (instruction == myInstructions[0]) return true; - if (instruction instanceof PushInstruction) return ((PushInstruction)instruction).getValue() instanceof DfaVariableValue; - if (instruction instanceof AssignInstruction) return ((AssignInstruction)instruction).getAssignedValue() != null; + if (!getReadVariables(instruction).isEmpty() || getWrittenVariable(instruction) != null) return true; return instruction instanceof FinishElementInstruction || - instruction instanceof FlushVariableInstruction || instruction instanceof GotoInstruction || instruction instanceof ConditionalGotoInstruction || instruction instanceof ReturnInstruction; @@ -124,34 +169,24 @@ public class LiveVariablesAnalyzer { } } - if (instruction instanceof AssignInstruction) { - DfaValue value = ((AssignInstruction)instruction).getAssignedValue(); - if (value instanceof DfaVariableValue) { - liveVars = (BitSet)liveVars.clone(); - liveVars.clear(value.getID()); - for (DfaVariableValue var : myFactory.getVarFactory().getAllQualifiedBy((DfaVariableValue)value)) { - liveVars.clear(var.getID()); - } + DfaVariableValue written = getWrittenVariable(instruction); + if (written != null) { + liveVars = (BitSet)liveVars.clone(); + liveVars.clear(written.getID()); + for (DfaVariableValue var : myFactory.getVarFactory().getAllQualifiedBy(written)) { + liveVars.clear(var.getID()); } - } - - if (instruction instanceof PushInstruction) { - DfaValue value = ((PushInstruction)instruction).getValue(); - if (value instanceof DfaVariableValue) { - if (!((PushInstruction)instruction).isReferenceWrite() && !liveVars.get(value.getID())) { - liveVars = (BitSet)liveVars.clone(); + } else { + boolean cloned = false; + for (DfaVariableValue value : getReadVariables(instruction)) { + if (!liveVars.get(value.getID())) { + if (!cloned) { + liveVars = (BitSet)liveVars.clone(); + cloned = true; + } liveVars.set(value.getID()); } } - } else if (instruction instanceof FlushVariableInstruction) { - DfaVariableValue variable = ((FlushVariableInstruction)instruction).getVariable(); - if (variable != null) { - liveVars = (BitSet)liveVars.clone(); - liveVars.clear(variable.getID()); - for (DfaVariableValue var : myFactory.getVarFactory().getAllQualifiedBy(variable)) { - liveVars.clear(var.getID()); - } - } } return liveVars; diff --git a/java/java-impl/src/com/intellij/psi/impl/JavaRegExpHost.java b/java/java-impl/src/com/intellij/psi/impl/JavaRegExpHost.java index 21a03d7e2bc3..86ca15a074dd 100644 --- a/java/java-impl/src/com/intellij/psi/impl/JavaRegExpHost.java +++ b/java/java-impl/src/com/intellij/psi/impl/JavaRegExpHost.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -60,7 +60,7 @@ public class JavaRegExpHost implements RegExpLanguageHost { @Override public boolean supportsNamedGroupSyntax(RegExpGroup group) { - if (group.isRubyNamedGroup()) { + if (group.isNamedGroup()) { final Module module = ModuleUtilCore.findModuleForPsiElement(group); if (module != null) { final Sdk sdk = ModuleRootManager.getInstance(module).getSdk(); diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/DontFlushVariablesUsedInClosures.java b/java/java-tests/testData/inspection/dataFlow/fixture/DontFlushVariablesUsedInClosures.java new file mode 100644 index 000000000000..bc2ed3cfe2f1 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/DontFlushVariablesUsedInClosures.java @@ -0,0 +1,19 @@ +import org.jetbrains.annotations.Nullable; + +class Foo { + + void foo(final @Nullable String s, String s2) { + if (s2 == null) return; + if (s == null) return; + + System.out.println(s2); + + new Runnable() { + @Override + public void run() { + s.hashCode(); + } + }.run(); + } + +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java index dba230fbed32..cc86a456004f 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java @@ -242,6 +242,7 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase { public void testManyContinuesNotComplex() { doTest(); } public void testFinallyNotComplex() { doTest(); } public void testFlushFurtherUnusedVariables() { doTest(); } + public void testDontFlushVariablesUsedInClosures() { doTest(); } public void testVariablesDiverge() { doTest(); } public void testMergeByNullability() { doTest(); } diff --git a/java/java-tests/testSrc/com/intellij/index/IndexTest.java b/java/java-tests/testSrc/com/intellij/index/IndexTest.java index 4fcb40296a48..b3be1f9f4feb 100644 --- a/java/java-tests/testSrc/com/intellij/index/IndexTest.java +++ b/java/java-tests/testSrc/com/intellij/index/IndexTest.java @@ -15,19 +15,25 @@ */ package com.intellij.index; +import com.intellij.codeInsight.CodeInsightTestCase; import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.command.impl.CurrentEditorProvider; +import com.intellij.openapi.command.impl.UndoManagerImpl; +import com.intellij.openapi.command.undo.UndoManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileTypes.PlainTextFileType; import com.intellij.openapi.util.Factory; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry; import com.intellij.psi.*; import com.intellij.psi.impl.PsiManagerEx; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiSearchHelper; -import com.intellij.testFramework.IdeaTestCase; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.PsiTestUtil; import com.intellij.testFramework.SkipSlowTestLocally; @@ -47,7 +53,7 @@ import java.util.*; * Date: Dec 12, 2007 */ @SkipSlowTestLocally -public class IndexTest extends IdeaTestCase { +public class IndexTest extends CodeInsightTestCase { public void testUpdate() throws StorageException, IOException { final File storageFile = FileUtil.createTempFile("indextest", "storage"); @@ -208,8 +214,7 @@ public class IndexTest extends IdeaTestCase { VfsUtil.saveText(vFile, "class Foo {}"); final GlobalSearchScope scope = GlobalSearchScope.allScope(getProject()); - final JavaPsiFacade facade = JavaPsiFacade.getInstance(getProject()); - assertNotNull(facade.findClass("Foo", scope)); + assertNotNull(myJavaFacade.findClass("Foo", scope)); WriteCommandAction.runWriteCommandAction(null, new Runnable() { @Override public void run() { @@ -218,20 +223,20 @@ public class IndexTest extends IdeaTestCase { Document document = FileDocumentManager.getInstance().getDocument(vFile); document.deleteString(0, document.getTextLength()); - assertNotNull(facade.findClass("Foo", scope)); + assertNotNull(myJavaFacade.findClass("Foo", scope)); psiFile = null; PlatformTestUtil.tryGcSoftlyReachableObjects(); assertNull(((PsiManagerEx)PsiManager.getInstance(getProject())).getFileManager().getCachedPsiFile(vFile)); - PsiClass foo = facade.findClass("Foo", scope); + PsiClass foo = myJavaFacade.findClass("Foo", scope); assertNotNull(foo); assertTrue(foo.isValid()); assertEquals("class Foo {}", foo.getText()); assertTrue(foo.isValid()); PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - assertNull(facade.findClass("Foo", scope)); + assertNull(myJavaFacade.findClass("Foo", scope)); } }); } @@ -244,8 +249,7 @@ public class IndexTest extends IdeaTestCase { VfsUtil.saveText(vFile, ""); final GlobalSearchScope scope = GlobalSearchScope.allScope(getProject()); - final JavaPsiFacade facade = JavaPsiFacade.getInstance(getProject()); - assertNull(facade.findClass("Foo", scope)); + assertNull(myJavaFacade.findClass("Foo", scope)); WriteCommandAction.runWriteCommandAction(null, new Runnable() { @Override public void run() { @@ -259,11 +263,11 @@ public class IndexTest extends IdeaTestCase { FileDocumentManager.getInstance().saveDocument(document); assertTrue(count == PsiManager.getInstance(myProject).getModificationTracker().getModificationCount()); - assertNull(facade.findClass("Foo", scope)); + assertNull(myJavaFacade.findClass("Foo", scope)); PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - assertNotNull(facade.findClass("Foo", scope)); - assertNotNull(facade.findClass("Foo", scope).getText()); + assertNotNull(myJavaFacade.findClass("Foo", scope)); + assertNotNull(myJavaFacade.findClass("Foo", scope).getText()); // if Foo exists now, mod count should be different assertTrue(count != PsiManager.getInstance(myProject).getModificationTracker().getModificationCount()); } @@ -303,9 +307,45 @@ public class IndexTest extends IdeaTestCase { PsiDocumentManager.getInstance(myProject).commitAllDocuments(); assertEquals(" Foo", file.getText()); assertOneElement(PsiSearchHelper.SERVICE.getInstance(myProject).findFilesWithPlainTextWords("Foo")); - } }); } + public void testUndoToFileContentForUnsavedCommittedDocument() throws IOException { + VirtualFile dir = getVirtualFile(createTempDirectory()); + PsiTestUtil.addSourceContentToRoots(myModule, dir); + + final VirtualFile vFile = createChildData(dir, "Foo.java"); + VfsUtil.saveText(vFile, "class Foo {}"); + ((VirtualFileSystemEntry)vFile).setModificationStamp(0); // as unchanged file + + final Document document = FileDocumentManager.getInstance().getDocument(vFile); + assertTrue(document != null && document.getModificationStamp() == 0); + final GlobalSearchScope scope = GlobalSearchScope.projectScope(myProject); + assertNotNull(myJavaFacade.findClass("Foo", scope)); + + WriteCommandAction.runWriteCommandAction(myProject, new Runnable() { + @Override + public void run() { + document.insertString(0, "import Bar;\n"); + PsiDocumentManager.getInstance(myProject).commitAllDocuments(); + assertNotNull(myJavaFacade.findClass("Foo", scope)); + } + }); + + final UndoManager undoManager = UndoManager.getInstance(getProject()); + final FileEditor selectedEditor = FileEditorManager.getInstance(myProject).openFile(vFile, false)[0]; + ((UndoManagerImpl)undoManager).setEditorProvider(new CurrentEditorProvider() { + @Override + public FileEditor getCurrentEditor() { + return selectedEditor; + } + }); + + assertTrue(undoManager.isUndoAvailable(selectedEditor)); + FileDocumentManager.getInstance().saveDocument(document); + undoManager.undo(selectedEditor); + + assertNotNull(myJavaFacade.findClass("Foo", scope)); + } } diff --git a/java/java-tests/testSrc/com/intellij/projectView/ProjectTreeSortingTest.java b/java/java-tests/testSrc/com/intellij/projectView/ProjectTreeSortingTest.java index cc06d15c396e..b25ca382f2fb 100644 --- a/java/java-tests/testSrc/com/intellij/projectView/ProjectTreeSortingTest.java +++ b/java/java-tests/testSrc/com/intellij/projectView/ProjectTreeSortingTest.java @@ -132,11 +132,11 @@ public class ProjectTreeSortingTest extends BaseProjectViewTestCase { ((ProjectViewImpl)myProjectView).setFoldersAlwaysOnTop(false); assertTree("-foldersOnTop\n" + " a.java\n" + + " +b.java\n" + " c.java\n" + " a.txt\n" + - " c.txt\n" + - " +b.java\n" + - " +b.txt\n"); + " +b.txt\n"+ + " c.txt\n"); } public void testSortByTypeBetweenFilesAndFolders() throws Exception { @@ -156,11 +156,11 @@ public class ProjectTreeSortingTest extends BaseProjectViewTestCase { assertTree("-sortByTypeBetweenFilesAndFolders\n" + " a.java\n" + " b.java\n" + + " +a.java_folder\n" + + " +b.java_folder\n" + " a.txt\n" + " b.txt\n" + - " +a.java_folder\n" + " +a_folder\n" + - " +b.java_folder\n" + " +b_folder\n"); } diff --git a/json/src/com/intellij/json/formatter/JsonBlock.java b/json/src/com/intellij/json/formatter/JsonBlock.java index 2dccd347e177..307e4a7fbc59 100644 --- a/json/src/com/intellij/json/formatter/JsonBlock.java +++ b/json/src/com/intellij/json/formatter/JsonBlock.java @@ -1,9 +1,7 @@ package com.intellij.json.formatter; import com.intellij.formatting.*; -import com.intellij.json.JsonElementTypes; import com.intellij.json.JsonLanguage; -import com.intellij.json.JsonParserDefinition; import com.intellij.json.psi.JsonArray; import com.intellij.json.psi.JsonObject; import com.intellij.json.psi.JsonProperty; @@ -23,18 +21,19 @@ import org.jetbrains.annotations.Nullable; import java.util.List; -import static com.intellij.json.JsonParserDefinition.JSON_BRACES; -import static com.intellij.json.JsonParserDefinition.JSON_BRACKETS; +import static com.intellij.json.JsonElementTypes.*; +import static com.intellij.json.JsonParserDefinition.*; import static com.intellij.json.formatter.JsonCodeStyleSettings.PropertyAlignment.ALIGN_ON_COLON; import static com.intellij.json.formatter.JsonCodeStyleSettings.PropertyAlignment.ALIGN_ON_VALUE; +import static com.intellij.json.psi.JsonPsiUtil.hasElementType; /** * @author Mikhail Golubev */ public class JsonBlock implements ASTBlock { - private static final TokenSet OPEN_BRACES = TokenSet.create(JsonElementTypes.L_BRACKET, JsonElementTypes.L_CURLY); - private static final TokenSet CLOSE_BRACES = TokenSet.create(JsonElementTypes.R_BRACKET, JsonElementTypes.R_CURLY); - private static final TokenSet BRACES = TokenSet.orSet(OPEN_BRACES, CLOSE_BRACES); + private static final TokenSet JSON_OPEN_BRACES = TokenSet.create(L_BRACKET, L_CURLY); + private static final TokenSet JSON_CLOSE_BRACES = TokenSet.create(R_BRACKET, R_CURLY); + private static final TokenSet JSON_ALL_BRACES = TokenSet.orSet(JSON_OPEN_BRACES, JSON_CLOSE_BRACES); private final JsonBlock myParent; @@ -48,8 +47,6 @@ public class JsonBlock implements ASTBlock { // lazy initialized on first call to #getSubBlocks() private List mySubBlocks = null; - private final Alignment myChildAlignment = Alignment.createAlignment(); - private final Alignment myPropertyValueAlignment; private final Wrap myChildWrap; @@ -111,28 +108,35 @@ public class JsonBlock implements ASTBlock { } private Block makeSubBlock(@NotNull ASTNode childNode) { - final IElementType childNodeType = childNode.getElementType(); - Indent indent = Indent.getNoneIndent(); Alignment alignment = null; Wrap wrap = null; - JsonCodeStyleSettings customSettings = getCustomSettings(); - if (isContainer() && childNodeType != JsonElementTypes.COMMA && !BRACES.contains(childNodeType)) { - assert myChildWrap != null && myChildAlignment != null; - wrap = myChildWrap; - alignment = myChildAlignment; - indent = Indent.getNormalIndent(); + final JsonCodeStyleSettings customSettings = getCustomSettings(); + if (hasElementType(myNode, JSON_CONTAINERS)) { + if (!hasElementType(childNode, COMMA) && !hasElementType(childNode, JSON_ALL_BRACES)) { + assert myChildWrap != null; + wrap = myChildWrap; + indent = Indent.getNormalIndent(); + } + else if (hasElementType(childNode, JSON_OPEN_BRACES)) { + if (JsonPsiUtil.isPropertyValue(myPsiElement) && customSettings.PROPERTY_ALIGNMENT == ALIGN_ON_VALUE) { + // WEB-13587 Align compound values on opening brace/bracket, not the whole block + assert myParent != null && myParent.myParent != null && myParent.myParent.myPropertyValueAlignment != null; + alignment = myParent.myParent.myPropertyValueAlignment; + } + } } // Handle properties alignment - else if (myNode.getElementType() == JsonElementTypes.PROPERTY) { - assert myParent.myNode.getElementType() == JsonElementTypes.OBJECT; - assert myParent.myPropertyValueAlignment != null; - if (childNode.getElementType() == JsonElementTypes.COLON && customSettings.PROPERTY_ALIGNMENT == ALIGN_ON_COLON) { + else if (hasElementType(myNode, PROPERTY) ) { + assert myParent != null && myParent.myPropertyValueAlignment != null; + if (hasElementType(childNode, COLON) && customSettings.PROPERTY_ALIGNMENT == ALIGN_ON_COLON) { alignment = myParent.myPropertyValueAlignment; } else if (JsonPsiUtil.isPropertyValue(childNode.getPsi()) && customSettings.PROPERTY_ALIGNMENT == ALIGN_ON_VALUE) { - alignment = myParent.myPropertyValueAlignment; + if (!hasElementType(childNode, JSON_CONTAINERS)) { + alignment = myParent.myPropertyValueAlignment; + } } } return new JsonBlock(this, childNode, mySettings, alignment, indent, wrap); @@ -160,17 +164,17 @@ public class JsonBlock implements ASTBlock { @Override public Spacing getSpacing(@Nullable Block child1, @NotNull Block child2) { final CommonCodeStyleSettings commonSettings = getCommonSettings(); - final IElementType leftChildType = child1 instanceof JsonBlock ? ((JsonBlock)child1).myNode.getElementType() : null; - final IElementType rightChildType = child2 instanceof JsonBlock ? ((JsonBlock)child2).myNode.getElementType() : null; + final ASTNode leftChild = child1 instanceof JsonBlock ? ((JsonBlock)child1).myNode : null; + final ASTNode rightChild = child2 instanceof JsonBlock ? ((JsonBlock)child2).myNode : null; // This causes braces/brackets to be on their own lines if whole object/array spans several lines. - if (leftChildType != null && rightChildType != null) { - if (JSON_BRACES.contains(leftChildType) ^ JSON_BRACES.contains(rightChildType)) { + if (leftChild != null && rightChild != null) { + if (hasElementType(leftChild, JSON_BRACES) ^ hasElementType(rightChild, JSON_BRACES)) { final int numSpaces = commonSettings.SPACE_WITHIN_BRACES ? 1 : 0; return Spacing.createDependentLFSpacing(numSpaces, numSpaces, myNode.getTextRange(), commonSettings.KEEP_LINE_BREAKS, commonSettings.KEEP_BLANK_LINES_IN_CODE); } - else if (JSON_BRACKETS.contains(leftChildType) ^ JSON_BRACKETS.contains(rightChildType)) { + else if (hasElementType(leftChild, JSON_BRACKETS) ^ hasElementType(rightChild, JSON_BRACKETS)) { final int numSpaces = commonSettings.SPACE_WITHIN_BRACKETS ? 1 : 0; return Spacing.createDependentLFSpacing(numSpaces, numSpaces, myNode.getTextRange(), commonSettings.KEEP_LINE_BREAKS, @@ -183,8 +187,11 @@ public class JsonBlock implements ASTBlock { @NotNull @Override public ChildAttributes getChildAttributes(int newChildIndex) { - if (isContainer()) { - return new ChildAttributes(Indent.getNormalIndent(), myChildAlignment); + if (hasElementType(myNode, JSON_CONTAINERS)) { + // WEB-13675: For some reason including alignment in child attributes causes + // indents to consist solely of spaces when both USE_TABS and SMART_TAB + // options are enabled. + return new ChildAttributes(Indent.getNormalIndent(), null); } // Will use continuation indent for cases like { "foo" } return new ChildAttributes(null, null); @@ -192,15 +199,14 @@ public class JsonBlock implements ASTBlock { @Override public boolean isIncomplete() { - IElementType nodeType = myNode.getElementType(); - ASTNode lastChildNode = myNode.getLastChildNode(); - if (nodeType == JsonElementTypes.OBJECT) { - return lastChildNode != null && lastChildNode.getElementType() != JsonElementTypes.R_CURLY; + final ASTNode lastChildNode = myNode.getLastChildNode(); + if (hasElementType(myNode, OBJECT)) { + return lastChildNode != null && lastChildNode.getElementType() != R_CURLY; } - else if (nodeType == JsonElementTypes.ARRAY) { - return lastChildNode != null && lastChildNode.getElementType() != JsonElementTypes.R_BRACKET; + else if (hasElementType(myNode, ARRAY)) { + return lastChildNode != null && lastChildNode.getElementType() != R_BRACKET; } - else if (myPsiElement instanceof JsonProperty) { + else if (hasElementType(myNode, PROPERTY)) { return ((JsonProperty)myPsiElement).getValue() == null; } return false; @@ -215,10 +221,6 @@ public class JsonBlock implements ASTBlock { return node.getElementType() == TokenType.WHITE_SPACE || node.getTextLength() == 0; } - private boolean isContainer() { - return JsonParserDefinition.JSON_CONTAINERS.contains(myNode.getElementType()); - } - private JsonCodeStyleSettings getCustomSettings() { return mySettings.getCustomSettings(JsonCodeStyleSettings.class); } diff --git a/json/src/com/intellij/json/formatter/JsonCodeStylePanel.java b/json/src/com/intellij/json/formatter/JsonCodeStylePanel.java index c5c78f78227b..fa858ab98d95 100644 --- a/json/src/com/intellij/json/formatter/JsonCodeStylePanel.java +++ b/json/src/com/intellij/json/formatter/JsonCodeStylePanel.java @@ -23,13 +23,16 @@ import java.awt.event.ItemListener; * @author Mikhail Golubev */ public class JsonCodeStylePanel extends CodeStyleAbstractPanel { - public static final String SAMPLE = "{\n" + - " \"longKeyName\": true,\n" + - " \"short\": false,\n" + - "\n" + - " \"group2-longKeyName\": null,\n" + - " \"group2-short\": 42\n" + - "}"; + public static final String ALIGNMENT_SAMPLE = "{\n" + + " \"foo\": {\n" + + " \"bar\": true,\n" + + " \"baz\": false\n" + + " },\n" + + " \"quux\": [\n" + + " 1, 2.0, 3e0, 4.0e0\n" + + " ],\n" + + " \"longPropertyName\": null\n" + + "}"; private JComboBox myPropertiesAlignmentCombo; private JPanel myPreviewPanel; @@ -59,7 +62,6 @@ public class JsonCodeStylePanel extends CodeStyleAbstractPanel { } } }); - } @Override @@ -82,7 +84,7 @@ public class JsonCodeStylePanel extends CodeStyleAbstractPanel { @Nullable @Override protected String getPreviewText() { - return SAMPLE; + return ALIGNMENT_SAMPLE; } @Override diff --git a/json/src/com/intellij/json/psi/JsonPsiUtil.java b/json/src/com/intellij/json/psi/JsonPsiUtil.java index e3520f7526b1..0b9a151212e6 100644 --- a/json/src/com/intellij/json/psi/JsonPsiUtil.java +++ b/json/src/com/intellij/json/psi/JsonPsiUtil.java @@ -5,6 +5,7 @@ import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import com.intellij.psi.TokenType; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; import static com.intellij.json.JsonParserDefinition.JSON_COMMENTARIES; @@ -86,4 +87,35 @@ public class JsonPsiUtil { } return lastSeen.getPsi(); } + + /** + * Check that element type of the given AST node belongs to the token set. + *

+ * It slightly less verbose than {@code set.contains(node.getElementType())} and overloaded methods with the same name + * allow check ASTNode/PsiElement against both concrete element types and token sets in uniform way. + */ + public static boolean hasElementType(@NotNull ASTNode node, @NotNull TokenSet set) { + return set.contains(node.getElementType()); + } + + /** + * @see #hasElementType(com.intellij.lang.ASTNode, com.intellij.psi.tree.TokenSet) + */ + public static boolean hasElementType(@NotNull ASTNode node, IElementType... types) { + return hasElementType(node, TokenSet.create(types)); + } + + /** + * @see #hasElementType(com.intellij.lang.ASTNode, com.intellij.psi.tree.TokenSet) + */ + public static boolean hasElementType(@NotNull PsiElement element, @NotNull TokenSet set) { + return element.getNode() != null && hasElementType(element.getNode(), set); + } + + /** + * @see #hasElementType(com.intellij.lang.ASTNode, com.intellij.psi.tree.IElementType...) + */ + public static boolean hasElementType(@NotNull PsiElement element, IElementType... types) { + return element.getNode() != null && hasElementType(element.getNode(), types); + } } diff --git a/json/tests/test/com/intellij/json/JsonEditingTest.java b/json/tests/test/com/intellij/json/JsonEditingTest.java index bb6f5088c89c..42421979f490 100644 --- a/json/tests/test/com/intellij/json/JsonEditingTest.java +++ b/json/tests/test/com/intellij/json/JsonEditingTest.java @@ -3,6 +3,9 @@ package com.intellij.json; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.util.Computable; import com.intellij.psi.PsiFile; +import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import org.jetbrains.annotations.NotNull; /** @@ -37,4 +40,22 @@ public class JsonEditingTest extends JsonTestCase { public void testNormalIndentAfterPropertyWithoutComma() { doTest("\n"); } + + // WEB-13675 + public void testIndentWithTabsWhenSmartTabEnabled() { + CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(myFixture.getProject()); + CommonCodeStyleSettings.IndentOptions indentOptions = settings.getCommonSettings(JsonLanguage.INSTANCE).getIndentOptions(); + assertNotNull(indentOptions); + CommonCodeStyleSettings.IndentOptions oldSettings = (CommonCodeStyleSettings.IndentOptions)indentOptions.clone(); + indentOptions.TAB_SIZE = 4; + indentOptions.INDENT_SIZE = 4; + indentOptions.USE_TAB_CHARACTER = true; + indentOptions.SMART_TABS = true; + try { + doTest("\n\"baz\""); + } + finally { + indentOptions.copyFrom(oldSettings); + } + } } diff --git a/json/tests/testData/editing/IndentWithTabsWhenSmartTabEnabled.after.json b/json/tests/testData/editing/IndentWithTabsWhenSmartTabEnabled.after.json new file mode 100644 index 000000000000..152513cad497 --- /dev/null +++ b/json/tests/testData/editing/IndentWithTabsWhenSmartTabEnabled.after.json @@ -0,0 +1,5 @@ +{ + "foo": true, + "bar": false, + "baz" +} \ No newline at end of file diff --git a/json/tests/testData/editing/IndentWithTabsWhenSmartTabEnabled.json b/json/tests/testData/editing/IndentWithTabsWhenSmartTabEnabled.json new file mode 100644 index 000000000000..69824365e9e8 --- /dev/null +++ b/json/tests/testData/editing/IndentWithTabsWhenSmartTabEnabled.json @@ -0,0 +1,4 @@ +{ + "foo": true, + "bar": false, +} \ No newline at end of file diff --git a/json/tests/testData/formatting/AlignPropertiesOnColon.json b/json/tests/testData/formatting/AlignPropertiesOnColon.json index e6bb1d6956be..c71adabb752f 100644 --- a/json/tests/testData/formatting/AlignPropertiesOnColon.json +++ b/json/tests/testData/formatting/AlignPropertiesOnColon.json @@ -1,5 +1,19 @@ { - "a": 1, - "aaa": 2, - "aaaaa": 3 + "require-dev": { + "phpunit/phpunit": "~3.7", + "phpunit/phpunit-selenium": "@stable", + "phpunit/phpunit-story": "@stable", + "phpunit/dbunit": "@stable" + }, + "minimum-stability": "dev", + "autoload": { + "psr-4": { + "DreamFactory\\Yii\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-develop": "1.5.x-dev" + } + } } \ No newline at end of file diff --git a/json/tests/testData/formatting/AlignPropertiesOnColon_after.json b/json/tests/testData/formatting/AlignPropertiesOnColon_after.json index d8c115391024..7a673e8c3c21 100644 --- a/json/tests/testData/formatting/AlignPropertiesOnColon_after.json +++ b/json/tests/testData/formatting/AlignPropertiesOnColon_after.json @@ -1,5 +1,19 @@ { - "a" : 1, - "aaa" : 2, - "aaaaa": 3 + "require-dev" : { + "phpunit/phpunit" : "~3.7", + "phpunit/phpunit-selenium": "@stable", + "phpunit/phpunit-story" : "@stable", + "phpunit/dbunit" : "@stable" + }, + "minimum-stability": "dev", + "autoload" : { + "psr-4": { + "DreamFactory\\Yii\\": "src/" + } + }, + "extra" : { + "branch-alias": { + "dev-develop": "1.5.x-dev" + } + } } \ No newline at end of file diff --git a/json/tests/testData/formatting/AlignPropertiesOnValue.json b/json/tests/testData/formatting/AlignPropertiesOnValue.json index e6bb1d6956be..c71adabb752f 100644 --- a/json/tests/testData/formatting/AlignPropertiesOnValue.json +++ b/json/tests/testData/formatting/AlignPropertiesOnValue.json @@ -1,5 +1,19 @@ { - "a": 1, - "aaa": 2, - "aaaaa": 3 + "require-dev": { + "phpunit/phpunit": "~3.7", + "phpunit/phpunit-selenium": "@stable", + "phpunit/phpunit-story": "@stable", + "phpunit/dbunit": "@stable" + }, + "minimum-stability": "dev", + "autoload": { + "psr-4": { + "DreamFactory\\Yii\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-develop": "1.5.x-dev" + } + } } \ No newline at end of file diff --git a/json/tests/testData/formatting/AlignPropertiesOnValue_after.json b/json/tests/testData/formatting/AlignPropertiesOnValue_after.json index 0cebf089466a..d4269bcc90b6 100644 --- a/json/tests/testData/formatting/AlignPropertiesOnValue_after.json +++ b/json/tests/testData/formatting/AlignPropertiesOnValue_after.json @@ -1,5 +1,19 @@ { - "a": 1, - "aaa": 2, - "aaaaa": 3 + "require-dev": { + "phpunit/phpunit": "~3.7", + "phpunit/phpunit-selenium": "@stable", + "phpunit/phpunit-story": "@stable", + "phpunit/dbunit": "@stable" + }, + "minimum-stability": "dev", + "autoload": { + "psr-4": { + "DreamFactory\\Yii\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-develop": "1.5.x-dev" + } + } } \ No newline at end of file diff --git a/json/tests/testData/mover/ArraySelectionMovedDown.json b/json/tests/testData/mover/ArraySelectionMovedDown.json index 476b56d42dea..81e4dc2bcd0e 100644 --- a/json/tests/testData/mover/ArraySelectionMovedDown.json +++ b/json/tests/testData/mover/ArraySelectionMovedDown.json @@ -1,5 +1,8 @@ [ - 1, [2], [true, - false], + 1, [2], + [ + true, + false + ], null ] \ No newline at end of file diff --git a/json/tests/testData/mover/ArraySelectionMovedDown_afterDown.json b/json/tests/testData/mover/ArraySelectionMovedDown_afterDown.json index 9db514b06905..1a7a49635d95 100644 --- a/json/tests/testData/mover/ArraySelectionMovedDown_afterDown.json +++ b/json/tests/testData/mover/ArraySelectionMovedDown_afterDown.json @@ -1,5 +1,8 @@ [ null, - 1, [2], [true, - false] + 1, [2], + [ + true, + false + ] ] \ No newline at end of file diff --git a/json/tests/testData/mover/ObjectSelectionMovedDown.json b/json/tests/testData/mover/ObjectSelectionMovedDown.json index 57efbe402072..ed363c1d3d6f 100644 --- a/json/tests/testData/mover/ObjectSelectionMovedDown.json +++ b/json/tests/testData/mover/ObjectSelectionMovedDown.json @@ -1,6 +1,10 @@ { - "foo": false, "bar": 42, - "baz": [1, 2, - 3], + "foo": false, + "bar": 42, + "baz": [ + 1, + 2, + 3 + ], "quux": null } \ No newline at end of file diff --git a/json/tests/testData/mover/ObjectSelectionMovedDown_afterDown.json b/json/tests/testData/mover/ObjectSelectionMovedDown_afterDown.json index 860d3b5d3783..ebf686822340 100644 --- a/json/tests/testData/mover/ObjectSelectionMovedDown_afterDown.json +++ b/json/tests/testData/mover/ObjectSelectionMovedDown_afterDown.json @@ -1,6 +1,10 @@ { + "foo": false, "quux": null, - "foo": false, "bar": 42, - "baz": [1, 2, - 3] + "bar": 42, + "baz": [ + 1, + 2, + 3 + ] } \ No newline at end of file diff --git a/platform/core-impl/src/com/intellij/openapi/components/ComponentSerializationUtil.java b/platform/core-impl/src/com/intellij/openapi/components/ComponentSerializationUtil.java index 33eee1a79178..0093d0016881 100644 --- a/platform/core-impl/src/com/intellij/openapi/components/ComponentSerializationUtil.java +++ b/platform/core-impl/src/com/intellij/openapi/components/ComponentSerializationUtil.java @@ -35,7 +35,10 @@ public class ComponentSerializationUtil { public static void loadComponentState(@NotNull PersistentStateComponent configuration, @Nullable Element element) { if (element != null) { Class stateClass = getStateClass(configuration.getClass()); - configuration.loadState(XmlSerializer.deserialize(element, stateClass)); + S state = XmlSerializer.deserialize(element, stateClass); + if (state != null) { + configuration.loadState(state); + } } } } diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java index 918ebaa22425..34512a6fc714 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java @@ -493,7 +493,9 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { throwGuardedFragment(marker, offset, null, s.toString()); } - updateText(myText.insert(offset, ImmutableText.valueOf(s)), offset, null, s, false, LocalTimeCounter.currentTime()); + myText = myText.ensureChunked(); + ImmutableText newText = myText.insert(offset, ImmutableText.valueOf(s)); + updateText(newText, offset, null, newText.subtext(offset, offset + s.length()), false, LocalTimeCounter.currentTime()); trimToSize(); } @@ -511,14 +513,13 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { if (!isWritable()) throw new ReadOnlyModificationException(this); if (startOffset == endOffset) return; - CharSequence sToDelete = myText.subSequence(startOffset, endOffset); - RangeMarker marker = getRangeGuard(startOffset, endOffset); if (marker != null) { - throwGuardedFragment(marker, startOffset, sToDelete.toString(), null); + throwGuardedFragment(marker, startOffset, myText.subSequence(startOffset, endOffset).toString(), null); } - updateText(myText.delete(startOffset, endOffset), startOffset, sToDelete, null, false, LocalTimeCounter.currentTime()); + myText = myText.ensureChunked(); + updateText(myText.delete(startOffset, endOffset), startOffset, myText.subtext(startOffset, endOffset), null, false, LocalTimeCounter.currentTime()); } @Override @@ -582,7 +583,7 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { } CharSequence changedPart = s.subSequence(newStartInString, newEndInString); - CharSequence sToDelete = myText.subSequence(startOffset, endOffset); + CharSequence sToDelete = myText.subtext(startOffset, endOffset); RangeMarker guard = getRangeGuard(startOffset, endOffset); if (guard != null) { throwGuardedFragment(guard, startOffset, sToDelete.toString(), changedPart.toString()); @@ -593,7 +594,9 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { newText = (ImmutableText)s; } else { + myText = myText.ensureChunked(); newText = myText.delete(startOffset, endOffset).insert(startOffset, changedPart); + changedPart = newText.subtext(startOffset, startOffset + changedPart.length()); } updateText(newText, startOffset, sToDelete, changedPart, wholeTextReplaced, newModificationStamp); trimToSize(); diff --git a/platform/duplicates-analysis/src/com/intellij/dupLocator/DuplocatorSettings.java b/platform/duplicates-analysis/src/com/intellij/dupLocator/DuplocatorSettings.java index 66983d376eb6..d805b8319743 100644 --- a/platform/duplicates-analysis/src/com/intellij/dupLocator/DuplocatorSettings.java +++ b/platform/duplicates-analysis/src/com/intellij/dupLocator/DuplocatorSettings.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2007 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.dupLocator; import com.intellij.openapi.components.*; @@ -22,19 +21,13 @@ import com.intellij.util.xmlb.XmlSerializerUtil; import java.util.HashSet; import java.util.Set; -/** - * Created by IntelliJ IDEA. - * User: db - * Date: Apr 8, 2004 - * Time: 2:47:43 PM - * To change this template use File | Settings | File Templates. - */ @State( - name="DuplocatorSettings", + name = "DuplocatorSettings", storages = { - @Storage( - file = StoragePathMacros.APP_CONFIG + "/other.xml" - )} + @Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml"), + @Storage(file = StoragePathMacros.APP_CONFIG + "/duplocatorSettings.xml") + }, + storageChooser = LastStorageChooserForWrite.class ) public class DuplocatorSettings implements PersistentStateComponent { public boolean DISTINGUISH_VARIABLES = false; diff --git a/platform/duplicates-analysis/src/com/intellij/dupLocator/MultilanguageDuplocatorSettings.java b/platform/duplicates-analysis/src/com/intellij/dupLocator/MultilanguageDuplocatorSettings.java index 92fc5b3b3175..da840978ff4b 100644 --- a/platform/duplicates-analysis/src/com/intellij/dupLocator/MultilanguageDuplocatorSettings.java +++ b/platform/duplicates-analysis/src/com/intellij/dupLocator/MultilanguageDuplocatorSettings.java @@ -6,7 +6,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMExternalizable; import com.intellij.openapi.util.WriteExternalException; -import com.intellij.util.containers.HashMap; +import com.intellij.util.containers.hash.LinkedHashMap; import org.jdom.Element; import org.jetbrains.annotations.NotNull; @@ -17,14 +17,12 @@ import java.util.Map; */ @State( name = "MultiLanguageDuplocatorSettings", - storages = { - @Storage(file = StoragePathMacros.APP_CONFIG + "/duplocatorSettings.xml") - } + storages = @Storage(file = StoragePathMacros.APP_CONFIG + "/duplocatorSettings.xml") ) public class MultilanguageDuplocatorSettings implements PersistentStateComponent { private static final Logger LOG = Logger.getInstance("#com.intellij.dupLocator.MultiLanguageDuplocatorSettings"); - private final Map mySettingsMap = new HashMap(); + private final Map mySettingsMap = new LinkedHashMap(); public static MultilanguageDuplocatorSettings getInstance() { return ServiceManager.getService(MultilanguageDuplocatorSettings.class); diff --git a/platform/icons/src/general/combo3.png b/platform/icons/src/general/combo3.png new file mode 100644 index 000000000000..bfdd4c4627e5 Binary files /dev/null and b/platform/icons/src/general/combo3.png differ diff --git a/platform/icons/src/general/combo3@2x.png b/platform/icons/src/general/combo3@2x.png new file mode 100644 index 000000000000..b421be0bc84f Binary files /dev/null and b/platform/icons/src/general/combo3@2x.png differ diff --git a/platform/icons/src/general/combo3@2x_dark.png b/platform/icons/src/general/combo3@2x_dark.png new file mode 100644 index 000000000000..9313cace3c80 Binary files /dev/null and b/platform/icons/src/general/combo3@2x_dark.png differ diff --git a/platform/icons/src/general/combo3_dark.png b/platform/icons/src/general/combo3_dark.png new file mode 100644 index 000000000000..51040859202b Binary files /dev/null and b/platform/icons/src/general/combo3_dark.png differ diff --git a/platform/icons/src/welcome/createNewProject.png b/platform/icons/src/welcome/createNewProject.png index 3bf27883974b..0055e1840808 100644 Binary files a/platform/icons/src/welcome/createNewProject.png and b/platform/icons/src/welcome/createNewProject.png differ diff --git a/platform/icons/src/welcome/createNewProject@2x.png b/platform/icons/src/welcome/createNewProject@2x.png index 4486b9a4a326..7cf70232ada7 100644 Binary files a/platform/icons/src/welcome/createNewProject@2x.png and b/platform/icons/src/welcome/createNewProject@2x.png differ diff --git a/platform/icons/src/welcome/fromVCS.png b/platform/icons/src/welcome/fromVCS.png index 66f3057c27b5..052aa210f5d3 100644 Binary files a/platform/icons/src/welcome/fromVCS.png and b/platform/icons/src/welcome/fromVCS.png differ diff --git a/platform/icons/src/welcome/fromVCS@2x.png b/platform/icons/src/welcome/fromVCS@2x.png index 1734213448d9..1ce34f8ebc1a 100644 Binary files a/platform/icons/src/welcome/fromVCS@2x.png and b/platform/icons/src/welcome/fromVCS@2x.png differ diff --git a/platform/icons/src/welcome/importProject.png b/platform/icons/src/welcome/importProject.png index 9be1003c14fb..713adfbb14a4 100644 Binary files a/platform/icons/src/welcome/importProject.png and b/platform/icons/src/welcome/importProject.png differ diff --git a/platform/icons/src/welcome/importProject@2x.png b/platform/icons/src/welcome/importProject@2x.png index 687dcf809a99..e5243159e1bc 100644 Binary files a/platform/icons/src/welcome/importProject@2x.png and b/platform/icons/src/welcome/importProject@2x.png differ diff --git a/platform/icons/src/welcome/openProject.png b/platform/icons/src/welcome/openProject.png index 600188c9be32..ea39bc0f541c 100644 Binary files a/platform/icons/src/welcome/openProject.png and b/platform/icons/src/welcome/openProject.png differ diff --git a/platform/icons/src/welcome/openProject@2x.png b/platform/icons/src/welcome/openProject@2x.png index 35646a827e07..bc5992419652 100644 Binary files a/platform/icons/src/welcome/openProject@2x.png and b/platform/icons/src/welcome/openProject@2x.png differ diff --git a/platform/lang-impl/src/com/intellij/framework/detection/impl/exclude/DetectionExcludesConfigurable.java b/platform/lang-impl/src/com/intellij/framework/detection/impl/exclude/DetectionExcludesConfigurable.java index 6239cbbab4ac..8cf5f461baa8 100644 --- a/platform/lang-impl/src/com/intellij/framework/detection/impl/exclude/DetectionExcludesConfigurable.java +++ b/platform/lang-impl/src/com/intellij/framework/detection/impl/exclude/DetectionExcludesConfigurable.java @@ -256,9 +256,6 @@ public class DetectionExcludesConfigurable implements Configurable { @Nullable private ExcludesConfigurationState computeState() { - if (myModel.getItems().isEmpty() && myEnabledDetectionCheckBox.isSelected()) { - return null; - } final ExcludesConfigurationState state = new ExcludesConfigurationState(); state.setDetectionEnabled(myEnabledDetectionCheckBox.isSelected()); for (ExcludeListItem item : myModel.getItems()) { @@ -278,22 +275,20 @@ public class DetectionExcludesConfigurable implements Configurable { public void reset() { myModel.clear(); final ExcludesConfigurationState state = myConfiguration.getActualState(); - myEnabledDetectionCheckBox.setSelected(state == null || state.isDetectionEnabled()); - if (state != null) { - for (String typeId : state.getFrameworkTypes()) { - final FrameworkType frameworkType = FrameworkDetectorRegistry.getInstance().findFrameworkType(typeId); - myModel.add(frameworkType != null ? new ValidExcludeListItem(frameworkType, null) : new InvalidExcludeListItem(typeId, null)); + myEnabledDetectionCheckBox.setSelected(state.isDetectionEnabled()); + for (String typeId : state.getFrameworkTypes()) { + final FrameworkType frameworkType = FrameworkDetectorRegistry.getInstance().findFrameworkType(typeId); + myModel.add(frameworkType != null ? new ValidExcludeListItem(frameworkType, null) : new InvalidExcludeListItem(typeId, null)); + } + for (ExcludedFileState fileState : state.getFiles()) { + VirtualFile file = VirtualFileManager.getInstance().findFileByUrl(fileState.getUrl()); + final String typeId = fileState.getFrameworkType(); + if (typeId == null) { + myModel.add(file != null ? new ValidExcludeListItem(null, file) : new InvalidExcludeListItem(null, fileState.getUrl())); } - for (ExcludedFileState fileState : state.getFiles()) { - VirtualFile file = VirtualFileManager.getInstance().findFileByUrl(fileState.getUrl()); - final String typeId = fileState.getFrameworkType(); - if (typeId == null) { - myModel.add(file != null ? new ValidExcludeListItem(null, file) : new InvalidExcludeListItem(null, fileState.getUrl())); - } - else { - final FrameworkType frameworkType = FrameworkDetectorRegistry.getInstance().findFrameworkType(typeId); - myModel.add(frameworkType != null && file != null? new ValidExcludeListItem(frameworkType, file) : new InvalidExcludeListItem(typeId, fileState.getUrl())); - } + else { + final FrameworkType frameworkType = FrameworkDetectorRegistry.getInstance().findFrameworkType(typeId); + myModel.add(frameworkType != null && file != null? new ValidExcludeListItem(frameworkType, file) : new InvalidExcludeListItem(typeId, fileState.getUrl())); } } } diff --git a/platform/lang-impl/src/com/intellij/framework/detection/impl/exclude/DetectionExcludesConfigurationImpl.java b/platform/lang-impl/src/com/intellij/framework/detection/impl/exclude/DetectionExcludesConfigurationImpl.java index a110e3435984..e89c65197563 100644 --- a/platform/lang-impl/src/com/intellij/framework/detection/impl/exclude/DetectionExcludesConfigurationImpl.java +++ b/platform/lang-impl/src/com/intellij/framework/detection/impl/exclude/DetectionExcludesConfigurationImpl.java @@ -185,12 +185,9 @@ public class DetectionExcludesConfigurationImpl extends DetectionExcludesConfigu } } - @Nullable + @NotNull public ExcludesConfigurationState getActualState() { ensureOldSettingsLoaded(); - if (myExcludedFiles.isEmpty() && myExcludedFrameworks.isEmpty() && myDetectionEnabled) { - return null; - } final ExcludesConfigurationState state = new ExcludesConfigurationState(); state.setDetectionEnabled(myDetectionEnabled); diff --git a/platform/lang-impl/src/com/intellij/ide/RecentDirectoryProjectsManagerEx.java b/platform/lang-impl/src/com/intellij/ide/RecentDirectoryProjectsManagerEx.java index b9086439906b..c65aa04b91a1 100644 --- a/platform/lang-impl/src/com/intellij/ide/RecentDirectoryProjectsManagerEx.java +++ b/platform/lang-impl/src/com/intellij/ide/RecentDirectoryProjectsManagerEx.java @@ -15,10 +15,7 @@ */ package com.intellij.ide; -import com.intellij.openapi.components.RoamingType; -import com.intellij.openapi.components.State; -import com.intellij.openapi.components.Storage; -import com.intellij.openapi.components.StoragePathMacros; +import com.intellij.openapi.components.*; import com.intellij.openapi.project.Project; import com.intellij.platform.ModuleAttachProcessor; import com.intellij.util.messages.MessageBus; @@ -29,7 +26,11 @@ import org.jetbrains.annotations.NotNull; */ @State( name = "RecentDirectoryProjectsManager", - storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml", roamingType = RoamingType.DISABLED)} + storages = { + @Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml"), + @Storage(file = StoragePathMacros.APP_CONFIG + "/recentProjectDirectories.xml", roamingType = RoamingType.DISABLED) + }, + storageChooser = LastStorageChooserForWrite.class ) public class RecentDirectoryProjectsManagerEx extends RecentDirectoryProjectsManager { public RecentDirectoryProjectsManagerEx(MessageBus messageBus) { diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java index 16aa930b806a..ec0b9dd8b6c6 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java @@ -318,6 +318,14 @@ public class PsiDirectoryNode extends BasePsiNode implements Navig return null; } + @Override + public Comparable getTypeSortKey() { + VirtualFile file = getVirtualFile(); + if (file == null) return null; + String extension = file.getExtension(); + return extension == null ? null : new PsiFileNode.ExtensionSortKey(extension); + } + @Override public String getQualifiedNameSortKey() { final PsiDirectoryFactory factory = PsiDirectoryFactory.getInstance(getProject()); diff --git a/platform/lang-impl/src/com/intellij/lang/javascript/boilerplate/AbstractGithubTagDownloadedProjectGenerator.java b/platform/lang-impl/src/com/intellij/lang/javascript/boilerplate/AbstractGithubTagDownloadedProjectGenerator.java index 09bca34d2a24..6ab678bf722c 100644 --- a/platform/lang-impl/src/com/intellij/lang/javascript/boilerplate/AbstractGithubTagDownloadedProjectGenerator.java +++ b/platform/lang-impl/src/com/intellij/lang/javascript/boilerplate/AbstractGithubTagDownloadedProjectGenerator.java @@ -89,34 +89,22 @@ public abstract class AbstractGithubTagDownloadedProjectGenerator extends WebPro @NotNull File extractToDir, @NotNull GithubTagInfo tag) throws GeneratorException { File zipArchiveFile = getCacheFile(tag); - boolean brokenZip = true; - boolean unitTestMode = ApplicationManager.getApplication().isUnitTestMode(); - if (!unitTestMode && zipArchiveFile.isFile()) { + String primaryUrl = getPrimaryZipArchiveUrlForDownload(tag); + boolean downloaded = false; + if (primaryUrl != null) { try { - ZipUtil.unzipWithProgressSynchronously(project, getTitle(), zipArchiveFile, extractToDir, true); - brokenZip = false; - } - catch (GeneratorException ignored) { + downloadAndUnzip(project, primaryUrl, zipArchiveFile, extractToDir, false); + downloaded = true; + } catch (GeneratorException e) { + LOG.info("Can't download " + primaryUrl, e); + FileUtil.delete(zipArchiveFile); } } - if (brokenZip) { - String primaryUrl = getPrimaryZipArchiveUrlForDownload(tag); - boolean downloaded = false; - if (primaryUrl != null) { - try { - downloadAndUnzip(project, primaryUrl, zipArchiveFile, extractToDir, false); - downloaded = true; - } catch (GeneratorException e) { - LOG.info("Can't download " + primaryUrl, e); - FileUtil.delete(zipArchiveFile); - } - } - if (!downloaded) { - if (unitTestMode) { - throw new GeneratorException("Download " + tag.getZipballUrl() + " is skipped in unit test mode"); - } - downloadAndUnzip(project, tag.getZipballUrl(), zipArchiveFile, extractToDir, true); + if (!downloaded) { + if (ApplicationManager.getApplication().isUnitTestMode()) { + throw new GeneratorException("Download " + tag.getZipballUrl() + " is skipped in unit test mode"); } + downloadAndUnzip(project, tag.getZipballUrl(), zipArchiveFile, extractToDir, true); } } diff --git a/platform/lang-impl/src/com/intellij/refactoring/RefactoringSettings.java b/platform/lang-impl/src/com/intellij/refactoring/RefactoringSettings.java index e2952f9b5a53..a5ef4e198993 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/RefactoringSettings.java +++ b/platform/lang-impl/src/com/intellij/refactoring/RefactoringSettings.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.refactoring; import com.intellij.openapi.components.*; @@ -25,9 +24,10 @@ import com.intellij.util.xmlb.XmlSerializerUtil; @State( name = "BaseRefactoringSettings", storages = { - @Storage( - file = StoragePathMacros.APP_CONFIG + "/other.xml" - )} + @Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml"), + @Storage(file = StoragePathMacros.APP_CONFIG + "/baseRefactoring.xml") + }, + storageChooser = LastStorageChooserForWrite.class ) public class RefactoringSettings implements PersistentStateComponent { public static RefactoringSettings getInstance() { diff --git a/platform/platform-api/src/com/intellij/ide/GeneralSettings.java b/platform/platform-api/src/com/intellij/ide/GeneralSettings.java index 57128945ef5c..3be1a37f7094 100644 --- a/platform/platform-api/src/com/intellij/ide/GeneralSettings.java +++ b/platform/platform-api/src/com/intellij/ide/GeneralSettings.java @@ -15,9 +15,12 @@ */ package com.intellij.ide; +import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.components.*; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.xmlb.XmlSerializerUtil; import com.intellij.util.xmlb.annotations.OptionTag; +import com.intellij.util.xmlb.annotations.Transient; import org.intellij.lang.annotations.MagicConstant; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; @@ -38,7 +41,6 @@ public class GeneralSettings implements PersistentStateComponent { } JFrame frame = null; - if (project == null) { - final Component owner = IdeFocusManager.findInstance().getFocusOwner(); - if (owner != null) { - frame = UIUtil.getParentOfType(JFrame.class, owner); - } - if (frame == null) { - frame = WindowManager.getInstance().findVisibleFrame(); - } - } else { + final Component owner = IdeFocusManager.findInstance().getFocusOwner(); + if (owner != null) { + frame = UIUtil.getParentOfType(JFrame.class, owner); + } + if (frame == null) { + frame = WindowManager.getInstance().findVisibleFrame(); + } + if (project != null && (frame == null || (frame instanceof IdeFrame && project != ((IdeFrame)frame).getProject()))) { frame = WindowManager.getInstance().getFrame(project); } Rectangle screen = new Rectangle(0, 0, 0, 0); diff --git a/platform/platform-api/src/com/intellij/util/net/ssl/CertificateConfigurable.form b/platform/platform-api/src/com/intellij/util/net/ssl/CertificateConfigurable.form index 18c12cb56090..fc148671aeab 100644 --- a/platform/platform-api/src/com/intellij/util/net/ssl/CertificateConfigurable.form +++ b/platform/platform-api/src/com/intellij/util/net/ssl/CertificateConfigurable.form @@ -3,7 +3,7 @@ - + @@ -56,7 +56,7 @@ - + diff --git a/platform/platform-impl/src/com/intellij/ide/RecentDirectoryProjectsManager.java b/platform/platform-impl/src/com/intellij/ide/RecentDirectoryProjectsManager.java index 59b115a43105..5282f61543b6 100644 --- a/platform/platform-impl/src/com/intellij/ide/RecentDirectoryProjectsManager.java +++ b/platform/platform-impl/src/com/intellij/ide/RecentDirectoryProjectsManager.java @@ -15,10 +15,7 @@ */ package com.intellij.ide; -import com.intellij.openapi.components.RoamingType; -import com.intellij.openapi.components.State; -import com.intellij.openapi.components.Storage; -import com.intellij.openapi.components.StoragePathMacros; +import com.intellij.openapi.components.*; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.LocalFileSystem; @@ -34,7 +31,11 @@ import org.jetbrains.annotations.Nullable; */ @State( name = "RecentDirectoryProjectsManager", - storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml", roamingType = RoamingType.DISABLED)} + storages = { + @Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml"), + @Storage(file = StoragePathMacros.APP_CONFIG + "/recentProjectDirectories.xml", roamingType = RoamingType.DISABLED) + }, + storageChooser = LastStorageChooserForWrite.class ) public class RecentDirectoryProjectsManager extends RecentProjectsManagerBase { public RecentDirectoryProjectsManager(MessageBus messageBus) { diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaComboBoxUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaComboBoxUI.java index 0eba3d3ce28a..9c61666f3a2d 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaComboBoxUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaComboBoxUI.java @@ -199,7 +199,7 @@ public class DarculaComboBoxUI extends BasicComboBoxUI implements Border { public void paint(Graphics g, JComponent c) { final Container parent = c.getParent(); if (parent != null) { - g.setColor(parent.getBackground()); + g.setColor(isTableCellEditor(c) && editor != null ? editor.getBackground() : parent.getBackground()); g.fillRect(0, 0, c.getWidth(), c.getHeight()); } Rectangle r = rectangleForCurrentValue(); @@ -212,7 +212,7 @@ public class DarculaComboBoxUI extends BasicComboBoxUI implements Border { } private static boolean isTableCellEditor(JComponent c) { - return Boolean.TRUE.equals(c.getClientProperty("JComboBox.isTableCellEditor")); + return Boolean.TRUE.equals(c.getClientProperty("JComboBox.isTableCellEditor")) || c.getParent() instanceof JTable; } @Override diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaEditorTextFieldBorder.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaEditorTextFieldBorder.java index 4cb617e5440a..cf96ea6235f4 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaEditorTextFieldBorder.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaEditorTextFieldBorder.java @@ -32,7 +32,9 @@ import java.awt.*; public class DarculaEditorTextFieldBorder implements Border { @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { - if (isComboBoxEditor(c) || isCellEditor(c)) { + if (isComboBoxEditor(c) /*|| isCellEditor(c)*/) { + g.setColor(c.getBackground()); + g.fillRect(x, y, width, height); return; } final EditorTextField textField = UIUtil.getParentOfType(EditorTextField.class, c); @@ -65,8 +67,8 @@ public class DarculaEditorTextFieldBorder implements Border { @Override public Insets getBorderInsets(Component c) { - if (isComboBoxEditor(c) || isCellEditor(c)) { - return new InsetsUIResource(0,0,0,0); + if (isComboBoxEditor(c) /*|| isCellEditor(c)*/) { + return new InsetsUIResource(2,3,2,3); } return new InsetsUIResource(6, 7, 6, 7); } diff --git a/platform/platform-impl/src/com/intellij/ide/util/TipPanel.java b/platform/platform-impl/src/com/intellij/ide/util/TipPanel.java index 8ca9576795c5..b2221f632a89 100644 --- a/platform/platform-impl/src/com/intellij/ide/util/TipPanel.java +++ b/platform/platform-impl/src/com/intellij/ide/util/TipPanel.java @@ -24,6 +24,7 @@ import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.SimpleTextAttributes; import com.intellij.ui.components.JBLabel; import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; @@ -44,13 +45,13 @@ public class TipPanel extends JPanel { setLayout(new BorderLayout()); JLabel jlabel = new JLabel(AllIcons.General.Tip); jlabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); - JLabel jlabel1 = new JLabel(IdeBundle.message("label.did.you.know")); - Font font = jlabel1.getFont(); - jlabel1.setFont(font.deriveFont(Font.PLAIN, font.getSize() + 4)); + JLabel label1 = new JLabel(IdeBundle.message("label.did.you.know")); + Font font = label1.getFont(); + label1.setFont(font.deriveFont(Font.PLAIN, font.getSize() + 4)); JPanel jpanel = new JPanel(); jpanel.setLayout(new BorderLayout()); jpanel.add(jlabel, BorderLayout.WEST); - jpanel.add(jlabel1, BorderLayout.CENTER); + jpanel.add(label1, BorderLayout.CENTER); jpanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0)); add(jpanel, BorderLayout.NORTH); myBrowser = TipUIUtil.createTipBrowser(); @@ -63,7 +64,8 @@ public class TipPanel extends JPanel { final GeneralSettings settings = GeneralSettings.getInstance(); showOnStartCheckBox.setSelected(settings.isShowTipsOnStartup()); showOnStartCheckBox.addItemListener(new ItemListener() { - public void itemStateChanged(ItemEvent e) { + @Override + public void itemStateChanged(@NotNull ItemEvent e) { settings.setShowTipsOnStartup(e.getStateChange() == ItemEvent.SELECTED); } }); @@ -79,6 +81,7 @@ public class TipPanel extends JPanel { Collections.addAll(myTips, Extensions.getExtensions(TipAndTrickBean.EP_NAME)); } + @Override public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java index c4ac427f89b5..fdbba254571b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java @@ -771,15 +771,16 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec try { final FileEditorProvider provider = newProviders[i]; LOG.assertTrue(provider != null, "Provider for file "+file+" is null. All providers: "+Arrays.asList(newProviders)); - LOG.assertTrue(provider.accept(myProject, file), "Provider " + provider + " doesn't accept file " + file); - if ((provider instanceof AsyncFileEditorProvider)) { - builders[i] = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public AsyncFileEditorProvider.Builder compute() { - return ((AsyncFileEditorProvider)provider).createEditorAsync(myProject, file); + builders[i] = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public AsyncFileEditorProvider.Builder compute() { + if (myProject.isDisposed() || !file.isValid()) { + return null; } - }); - } + LOG.assertTrue(provider.accept(myProject, file), "Provider " + provider + " doesn't accept file " + file); + return provider instanceof AsyncFileEditorProvider ? ((AsyncFileEditorProvider)provider).createEditorAsync(myProject, file) : null; + } + }); } catch (Exception e) { LOG.error(e); diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsFilter.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsFilter.java index 1885a852c5da..fdd4fa96aaee 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsFilter.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsFilter.java @@ -22,6 +22,7 @@ import com.intellij.openapi.options.ConfigurableGroup; import com.intellij.openapi.options.SearchableConfigurable; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.ActionCallback; +import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.ui.DocumentAdapter; import com.intellij.ui.LightColors; import com.intellij.ui.SearchTextField; @@ -58,6 +59,11 @@ abstract class SettingsFilter extends ElementFilter.Active.Impl { @Override protected void textChanged(DocumentEvent event) { update(event.getType(), true, false); + // request focus if needed on changing the filter text + IdeFocusManager manager = IdeFocusManager.findInstanceByComponent(mySearch); + if (manager.getFocusedDescendantFor(mySearch) == null) { + manager.requestFocus(mySearch, true); + } } }); mySearch.getTextEditor().addMouseListener(new MouseAdapter() { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/FlatWelcomeFrame.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/FlatWelcomeFrame.java index 2d77629feeb5..d2a21a482e1a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/FlatWelcomeFrame.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/FlatWelcomeFrame.java @@ -46,6 +46,7 @@ import com.intellij.ui.*; import com.intellij.ui.border.CustomLineBorder; import com.intellij.ui.components.labels.ActionLink; import com.intellij.ui.components.panels.NonOpaquePanel; +import com.intellij.util.ui.EmptyIcon; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -59,7 +60,6 @@ import java.awt.event.*; import java.io.File; import java.io.InputStream; import java.net.URL; -import java.util.Arrays; /** * @author Konstantin Bulenkov @@ -92,6 +92,7 @@ public class FlatWelcomeFrame extends JFrame implements IdeFrame { } else { setSize(555, 460); } + setResizable(false); //int x = bounds.x + (bounds.width - getWidth()) / 2; //int y = bounds.y + (bounds.height - getHeight()) / 2; Point location = DimensionService.getInstance().getLocation(WelcomeFrame.DIMENSION_KEY, null); @@ -166,13 +167,29 @@ public class FlatWelcomeFrame extends JFrame implements IdeFrame { } public static Color getMainBackground() { - return new JBColor(new Color(0xf5f6f8), new Color(0x3c3f41)); + return new JBColor(0xf7f7f7, 0x45474a); } - public static Color getProjectsBackGround() { - return new JBColor(Gray.xFF, new Color(58, 61, 63)); + public static Color getProjectsBackground() { + return new JBColor(Gray.xFF, Gray.x39); } + public static Color getLinkNormalColor() { + return new JBColor(Gray._0, Gray.xBB); + } + + public static Color getListSelectionColor(boolean hasFocus) { + return hasFocus ? new JBColor(0x3875d6, 0x4b6eaf) : new JBColor(Gray.xDD, Gray.x45); + } + + public static Color getActionLinkSelectionColor() { + return new JBColor(0xdbe5f5, 0x485875); + } + + public static JBColor getSeparatorColor() { + return new JBColor(Gray.xEC, new Color(72, 75, 78)); + } + private class FlatWelcomeScreen extends JPanel implements WelcomeScreen { public FlatWelcomeScreen() { super(new BorderLayout()); @@ -193,7 +210,7 @@ public class FlatWelcomeFrame extends JFrame implements IdeFrame { } private void removeIfNeeded() { - if (projectsList.getModel().getSize() == 0) { + if (RecentProjectsManager.getInstance().getRecentProjectsActions(false).length == 0) { FlatWelcomeScreen.this.remove(recentProjects); FlatWelcomeScreen.this.revalidate(); FlatWelcomeScreen.this.repaint(); @@ -205,6 +222,17 @@ public class FlatWelcomeFrame extends JFrame implements IdeFrame { removeIfNeeded(); } }); + projectsList.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + projectsList.repaint(); + } + + @Override + public void focusLost(FocusEvent e) { + projectsList.repaint(); + } + }); } } add(createBody(), BorderLayout.CENTER); @@ -224,17 +252,41 @@ public class FlatWelcomeFrame extends JFrame implements IdeFrame { } private JComponent createSettingsAndDocs() { - NonOpaquePanel toolbar = new NonOpaquePanel(); - toolbar.setLayout(new BoxLayout(toolbar, BoxLayout.X_AXIS)); - toolbar.add(createActionLink("Configure", IdeActions.GROUP_WELCOME_SCREEN_CONFIGURE, AllIcons.General.Settings)); - toolbar.add(createActionLink("Get Help", IdeActions.GROUP_WELCOME_SCREEN_DOC, null)); JPanel panel = new NonOpaquePanel(new BorderLayout()); + NonOpaquePanel toolbar = new NonOpaquePanel(); + AnAction register = ActionManager.getInstance().getAction("Register"); + boolean registeredVisible = false; + if (register != null) { + Presentation presentation = register.getTemplatePresentation(); + register.update(new AnActionEvent(null, DataManager.getInstance().getDataContext(this), + ActionPlaces.WELCOME_SCREEN, presentation, ActionManager.getInstance(), 0)); + if (presentation.isEnabled()) { + ActionLink registerLink = new ActionLink("Register", register); + registerLink.setNormalColor(getLinkNormalColor()); + NonOpaquePanel button = new NonOpaquePanel(new BorderLayout()); + button.setBorder(new EmptyBorder(4, 10, 4, 10)); + button.add(registerLink); + installFocusable(button, register, KeyEvent.VK_UP, KeyEvent.VK_RIGHT, true); + NonOpaquePanel wrap = new NonOpaquePanel(); + wrap.setBorder(new EmptyBorder(0, 10, 0, 0)); + wrap.add(button); + panel.add(wrap, BorderLayout.WEST); + registeredVisible = true; + } + } + + toolbar.setLayout(new BoxLayout(toolbar, BoxLayout.X_AXIS)); + toolbar.add(createActionLink("Configure", IdeActions.GROUP_WELCOME_SCREEN_CONFIGURE, AllIcons.General.Settings, !registeredVisible)); + toolbar.add(createActionLink("Get Help", IdeActions.GROUP_WELCOME_SCREEN_DOC, null, false)); + panel.add(toolbar, BorderLayout.EAST); + + panel.setBorder(new EmptyBorder(0,0,8,21)); return panel; } - private JComponent createActionLink(final String text, final String groupId, Icon icon) { + private JComponent createActionLink(final String text, final String groupId, Icon icon, boolean focusListOnLeft) { final Ref settings = new Ref(null); AnAction action = new AnAction() { @Override @@ -248,11 +300,12 @@ public class FlatWelcomeFrame extends JFrame implements IdeFrame { }; settings.set(new ActionLink(text, icon, action)); settings.get().setPaintUnderline(false); + settings.get().setNormalColor(getLinkNormalColor()); NonOpaquePanel panel = new NonOpaquePanel(new BorderLayout()); - panel.setBorder(new EmptyBorder(4, 16, 4, 4)); + panel.setBorder(new EmptyBorder(4, 10, 4, 10)); panel.add(settings.get()); - panel.add(new JLabel(AllIcons.General.Combo2), BorderLayout.EAST); - installFocusable(panel, action, KeyEvent.VK_UP, KeyEvent.VK_DOWN, !Arrays.asList("Get Help", "Register").contains(text)); + panel.add(createArrow(settings.get()), BorderLayout.EAST); + installFocusable(panel, action, KeyEvent.VK_UP, KeyEvent.VK_DOWN, focusListOnLeft); return panel; } @@ -264,12 +317,6 @@ public class FlatWelcomeFrame extends JFrame implements IdeFrame { DefaultActionGroup group = new DefaultActionGroup(); collectAllActions(group, quickStart); - // so, we sure this is the last action - final AnAction register = actionManager.getAction("WelcomeScreen.Register"); - if (register != null) { - group.add(register); - } - for (AnAction action : group.getChildren(null)) { JPanel button = new JPanel(new BorderLayout()); button.setOpaque(false); @@ -278,11 +325,22 @@ public class FlatWelcomeFrame extends JFrame implements IdeFrame { action.update(new AnActionEvent(null, DataManager.getInstance().getDataContext(this), ActionPlaces.WELCOME_SCREEN, presentation, ActionManager.getInstance(), 0)); if (presentation.isVisible()) { - ActionLink link = new ActionLink(presentation.getText(), presentation.getIcon(), action); + String text = presentation.getText(); + if (text.endsWith("...")) { + text = text.substring(0, text.length() - 3); + } + Icon icon = presentation.getIcon(); + if (icon.getIconHeight() != 16 || icon.getIconWidth() != 16) { + icon = EmptyIcon.ICON_16; + } + ActionLink link = new ActionLink(text, icon, action); link.setPaintUnderline(false); - link.setNormalColor(new JBColor(Gray._0, Gray.xBB)); - installFocusable(button, action, KeyEvent.VK_UP, KeyEvent.VK_DOWN, true); + link.setNormalColor(getLinkNormalColor()); button.add(link); + if (action instanceof WelcomePopupAction) { + button.add(createArrow(link), BorderLayout.EAST); + } + installFocusable(button, action, KeyEvent.VK_UP, KeyEvent.VK_DOWN, true); actions.add(button); } } @@ -306,7 +364,6 @@ public class FlatWelcomeFrame extends JFrame implements IdeFrame { private JComponent createLogo() { NonOpaquePanel panel = new NonOpaquePanel(new BorderLayout()); JLabel logo = new JLabel(IconLoader.getIcon(ApplicationInfoEx.getInstanceEx().getWelcomeScreenLogoUrl())); - logo.setBorder(new EmptyBorder(20, 0, 0, 0)); logo.setHorizontalAlignment(SwingConstants.CENTER); panel.add(logo, BorderLayout.NORTH); JLabel appName = new JLabel(ApplicationNamesInfo.getInstance().getFullProductName()); @@ -321,6 +378,7 @@ public class FlatWelcomeFrame extends JFrame implements IdeFrame { panel.add(appName); panel.add(version, BorderLayout.SOUTH); + panel.setBorder(new EmptyBorder(20, 10, 30, 10)); return panel; } @@ -350,8 +408,8 @@ public class FlatWelcomeFrame extends JFrame implements IdeFrame { private JComponent createRecentProjects() { JPanel panel = new JPanel(new BorderLayout()); panel.add(new NewRecentProjectPanel(this), BorderLayout.CENTER); - panel.setBackground(getProjectsBackGround()); - panel.setBorder(new CustomLineBorder(new JBColor(Gray.xEC, new Color(0x3c3f41)), 0,0,0,1)); + panel.setBackground(getProjectsBackground()); + panel.setBorder(new CustomLineBorder(getSeparatorColor(), 0,0,0,1)); return panel; } @@ -390,7 +448,7 @@ public class FlatWelcomeFrame extends JFrame implements IdeFrame { @Override public void focusGained(FocusEvent e) { comp.setOpaque(true); - comp.setBackground(new JBColor(new Color(0xd2e1f0), new Color(0x455565))); + comp.setBackground(getActionLinkSelectionColor()); } @Override @@ -479,6 +537,22 @@ public class FlatWelcomeFrame extends JFrame implements IdeFrame { } } + private static JLabel createArrow(final ActionLink link) { + JLabel arrow = new JLabel(AllIcons.General.Combo3); + arrow.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + arrow.setVerticalAlignment(SwingConstants.BOTTOM); + new ClickListener() { + @Override + public boolean onClick(@NotNull MouseEvent e, int clickCount) { + final MouseEvent newEvent = new MouseEvent(link, e.getID(), e.getWhen(), e.getModifiers(), e.getX(), e.getY(), e.getClickCount(), + e.isPopupTrigger(), e.getButton()); + link.doClick(newEvent); + return true; + } + }.installOn(arrow); + return arrow; + } + @Override public BalloonLayout getBalloonLayout() { return myBalloonLayout; diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/NewRecentProjectPanel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/NewRecentProjectPanel.java index f2152bd449c8..0d7fccb29982 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/NewRecentProjectPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/NewRecentProjectPanel.java @@ -37,17 +37,17 @@ public class NewRecentProjectPanel extends RecentProjectPanel { public NewRecentProjectPanel(WelcomeScreen screen) { super(screen); setBorder(null); - setBackground(FlatWelcomeFrame.getProjectsBackGround()); + setBackground(FlatWelcomeFrame.getProjectsBackground()); JScrollPane scrollPane = UIUtil.findComponentOfType(this, JScrollPane.class); if (scrollPane != null) { - scrollPane.setBackground(FlatWelcomeFrame.getProjectsBackGround()); + scrollPane.setBackground(FlatWelcomeFrame.getProjectsBackground()); scrollPane.setSize(245, 460); scrollPane.setMinimumSize(new Dimension(245, 460)); scrollPane.setPreferredSize(new Dimension(245, 460)); } ListWithFilter panel = UIUtil.findComponentOfType(this, ListWithFilter.class); if (panel != null) { - panel.setBackground(FlatWelcomeFrame.getProjectsBackGround()); + panel.setBackground(FlatWelcomeFrame.getProjectsBackground()); } } @@ -58,7 +58,7 @@ public class NewRecentProjectPanel extends RecentProjectPanel { @Override protected JBList createList(AnAction[] recentProjectActions, Dimension size) { final JBList list = super.createList(recentProjectActions, size); - list.setBackground(FlatWelcomeFrame.getProjectsBackGround()); + list.setBackground(FlatWelcomeFrame.getProjectsBackground()); list.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { @@ -87,12 +87,12 @@ public class NewRecentProjectPanel extends RecentProjectPanel { } @Override protected Color getListBackground(boolean isSelected, boolean hasFocus) { - return isSelected ? new Color(0x2484fd) : FlatWelcomeFrame.getProjectsBackGround(); + return isSelected ? FlatWelcomeFrame.getListSelectionColor(hasFocus) : FlatWelcomeFrame.getProjectsBackground(); } @Override protected Color getListForeground(boolean isSelected, boolean hasFocus) { - return UIUtil.getListForeground(isSelected); + return UIUtil.getListForeground(isSelected && hasFocus); } }; } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java index 2c2d68541bc6..f47c53330771 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java @@ -257,8 +257,8 @@ public class RecentProjectPanel extends JPanel { public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { ReopenProjectAction item = (ReopenProjectAction)value; - Color fore = getListForeground(isSelected, cellHasFocus); - Color back = getListBackground(isSelected, cellHasFocus); + Color fore = getListForeground(isSelected, list.hasFocus()); + Color back = getListBackground(isSelected, list.hasFocus()); myName.setForeground(fore); myPath.setForeground(isSelected ? fore : UIUtil.getInactiveTextColor()); diff --git a/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java b/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java index d41d0bb5ef18..88353779a83c 100644 --- a/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java @@ -57,6 +57,7 @@ import java.awt.geom.GeneralPath; import java.awt.geom.Rectangle2D; import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; +import java.util.List; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; @@ -792,6 +793,7 @@ public class BalloonImpl implements Balloon, IdeTooltip.Ui { private void hideAndDispose(final boolean ok) { if (myDisposed) return; myDisposed = true; + hideComboBoxPopups(); final Runnable disposeRunnable = new Runnable() { @Override @@ -827,6 +829,13 @@ public class BalloonImpl implements Balloon, IdeTooltip.Ui { myTracker = null; } + private void hideComboBoxPopups() { + List comboBoxes = UIUtil.findComponentsOfType(myComp, JComboBox.class); + for (JComboBox box : comboBoxes) { + box.hidePopup(); + } + } + protected void onDisposed() { } @Override diff --git a/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java b/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java index 7274d0930824..039868096f10 100644 --- a/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java +++ b/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java @@ -747,7 +747,7 @@ public class AbstractPopup implements JBPopup { Point xy = new Point(aScreenX, aScreenY); boolean adjustXY = true; - if (myDimensionServiceKey != null) { + if (myUseDimServiceForXYLocation && myDimensionServiceKey != null) { final Point storedLocation = DimensionService.getInstance().getLocation(myDimensionServiceKey, myProject); if (storedLocation != null) { xy = storedLocation; diff --git a/platform/platform-impl/src/com/intellij/util/ui/SwingHelper.java b/platform/platform-impl/src/com/intellij/util/ui/SwingHelper.java index 721e04469d24..488c52d14207 100644 --- a/platform/platform-impl/src/com/intellij/util/ui/SwingHelper.java +++ b/platform/platform-impl/src/com/intellij/util/ui/SwingHelper.java @@ -436,13 +436,10 @@ public class SwingHelper { textPane.setContentType(UIUtil.HTML_MIME); textPane.setEditable(false); if (background != null) { - textPane.setBackground(background); // e.g. UIUtil.getOptionPaneBackground() + textPane.setBackground(background); } else { textPane.setOpaque(false); - if (UIUtil.isUnderNimbusLookAndFeel()) { - textPane.setBackground(UIUtil.TRANSPARENT_COLOR); - } } textPane.setForeground(foreground != null ? foreground : UIUtil.getLabelForeground()); return textPane; diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index f80f272c8933..81e770d767b3 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -1009,8 +1009,8 @@ action.ChangeKeymap.text=Keymap action.ChangeKeymap.description=Change current keymap action.ChangeLaf.text=Look and Feel action.ChangeLaf.description=Change current Look\\&Feel -action.ChangeView.text=Screen Mode -action.ChangeView.description=Change screen mode +action.ChangeView.text=View Mode +action.ChangeView.description=Change view mode action.ChangeInspectionProfile.text=Switch Error Highlighting action.ChangeInspectionProfile.description=Change current editor inspection profile action.ChangeCustomizationSchema.text=Switch Customization Scheme diff --git a/platform/platform-resources-en/src/messages/OptionsBundle.properties b/platform/platform-resources-en/src/messages/OptionsBundle.properties index aa64f5d80717..1906440c7ecc 100644 --- a/platform/platform-resources-en/src/messages/OptionsBundle.properties +++ b/platform/platform-resources-en/src/messages/OptionsBundle.properties @@ -303,3 +303,7 @@ exportable.NotificationConfiguration.presentable.name=Notifications exportable.CodeInsightSettings.presentable.name=CodeInsight exportable.HttpConfigurable.presentable.name=HTTP Proxy exportable.KeymapManager.presentable.name=Key maps +exportable.UsageViewSettings.presentable.name=Usage View +exportable.BaseRefactoringSettings.presentable.name=Refactoring +exportable.DuplocatorSettings.presentable.name=Duplocator +exportable.MultiLanguageDuplocatorSettings.presentable.name=Duplocator diff --git a/platform/script-debugger/backend/src/org/jetbrains/rpc/ChannelBufferToString.java b/platform/script-debugger/backend/src/org/jetbrains/rpc/ChannelBufferToString.java index 0b18ebcd1eb2..bb776e55ea20 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/rpc/ChannelBufferToString.java +++ b/platform/script-debugger/backend/src/org/jetbrains/rpc/ChannelBufferToString.java @@ -3,6 +3,8 @@ package org.jetbrains.rpc; import com.intellij.util.text.StringFactory; import io.netty.buffer.ByteBuf; import io.netty.util.CharsetUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.nio.ByteBuffer; import java.nio.CharBuffer; @@ -29,7 +31,7 @@ public final class ChannelBufferToString { } } - public static CharBuffer readIntoCharBuffer(CharBuffer charBuffer, ByteBuf buffer, int byteCount) { + public static CharBuffer readIntoCharBuffer(@Nullable CharBuffer charBuffer, @NotNull ByteBuf buffer, int byteCount) { CharsetDecoder decoder = CharsetUtil.getDecoder(CharsetUtil.UTF_8); ByteBuffer in = buffer.nioBuffer(buffer.readerIndex(), byteCount); if (charBuffer == null) { @@ -52,4 +54,11 @@ public final class ChannelBufferToString { buffer.skipBytes(byteCount); return charBuffer; } + + public static void writeIntAsAscii(int value, @NotNull ByteBuf buffer) { + String string = Integer.toString(value); + for (int i = 0; i < string.length(); i++) { + buffer.writeByte(string.charAt(i)); + } + } } \ No newline at end of file diff --git a/platform/script-debugger/backend/src/org/jetbrains/rpc/MessageDecoder.java b/platform/script-debugger/backend/src/org/jetbrains/rpc/MessageDecoder.java new file mode 100644 index 000000000000..9d7e35198225 --- /dev/null +++ b/platform/script-debugger/backend/src/org/jetbrains/rpc/MessageDecoder.java @@ -0,0 +1,87 @@ +package org.jetbrains.rpc; + +import io.netty.buffer.ByteBuf; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.io.SimpleChannelInboundHandlerAdapter; + +import java.nio.CharBuffer; + +public abstract class MessageDecoder extends SimpleChannelInboundHandlerAdapter { + protected int contentLength; + protected final StringBuilder builder = new StringBuilder(64); + + private CharBuffer chunkedContent; + private int consumedContentByteCount = 0; + + protected final int parseContentLength() { + return parseInt(builder, 0, false, 10); + } + + @Nullable + protected String doReadContent(@NotNull ByteBuf buffer) { + int required = contentLength - consumedContentByteCount; + String result; + if (buffer.readableBytes() < required) { + if (chunkedContent == null) { + chunkedContent = CharBuffer.allocate(contentLength); + } + + int count = buffer.readableBytes(); + ChannelBufferToString.readIntoCharBuffer(chunkedContent, buffer, count); + consumedContentByteCount += count; + return null; + } + else if (chunkedContent != null) { + ChannelBufferToString.readIntoCharBuffer(chunkedContent, buffer, required); + result = ChannelBufferToString.charBufferToString(chunkedContent); + + chunkedContent = null; + consumedContentByteCount = 0; + return result; + } + else { + // we can produce char sequence CharSequence result = CharsetUtil.UTF_8.decode(buffer.toByteBuffer(buffer.readerIndex(), required)); + // but later, in JsonReaderEx, it will be toString in any case, so, in this case, intermediate java.nio.HeapCharBuffer will be created - so, we stay with String + return ChannelBufferToString.readString(buffer, required); + } + } + + /** + * Javolution - Java(TM) Solution for Real-Time and Embedded Systems + * Copyright (C) 2006 - Javolution (http://javolution.org/) + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software is + * freely granted, provided that this notice is preserved. + */ + private static int parseInt(final CharSequence value, final int start, final boolean isNegative, final int radix) { + final int end = value.length(); + int result = 0; // Accumulates negatively (avoid MIN_VALUE overflow). + int i = start; + for (; i < end; i++) { + char c = value.charAt(i); + int digit = (c <= '9') ? c - '0' + : ((c <= 'Z') && (c >= 'A')) ? c - 'A' + 10 + : ((c <= 'z') && (c >= 'a')) ? c - 'a' + 10 : -1; + if ((digit >= 0) && (digit < radix)) { + int newResult = result * radix - digit; + if (newResult > result) { + throw new NumberFormatException("Overflow parsing " + value.subSequence(start, end)); + } + result = newResult; + } + else { + break; + } + } + // Requires one valid digit character and checks for opposite overflow. + if ((result == 0) && ((end == 0) || (value.charAt(i - 1) != '0'))) { + throw new NumberFormatException("Invalid integer representation for " + value.subSequence(start, end)); + } + if ((result == Integer.MIN_VALUE) && !isNegative) { + throw new NumberFormatException("Overflow parsing " + value.subSequence(start, end)); + } + return isNegative ? result : -result; + } +} \ No newline at end of file diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/RemoteVmConnection.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/RemoteVmConnection.java index 6557de5130fe..753ec0c05cb9 100644 --- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/RemoteVmConnection.java +++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/RemoteVmConnection.java @@ -2,15 +2,22 @@ package org.jetbrains.debugger.connection; import com.intellij.ide.browsers.WebBrowser; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.AsyncResult; +import com.intellij.ui.ColoredListCellRenderer; +import com.intellij.ui.components.JBList; import com.intellij.util.Consumer; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.io.socketConnection.ConnectionStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.debugger.Vm; +import javax.swing.*; import java.net.InetSocketAddress; +import java.util.Collection; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicReference; @@ -87,4 +94,46 @@ public abstract class RemoteVmConnection extends VmConnection { } return callback; } + + @NotNull + public static AsyncResult chooseDebuggee(@NotNull final Collection targets, final int selectedIndex, @NotNull final Function itemToString) { + if (targets.size() == 1) { + return AsyncResult.done(ContainerUtil.getFirstItem(targets)); + } + + final AsyncResult result = new AsyncResult(); + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + final JBList list = new JBList(targets); + list.setCellRenderer(new ColoredListCellRenderer() { + @Override + protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) { + //noinspection unchecked + append(itemToString.fun((T)value)); + } + }); + list.setSelectedIndex(selectedIndex); + + JBPopupFactory.getInstance(). + createListPopupBuilder(list). + setTitle("Choose Page to debug"). + setItemChoosenCallback(new Runnable() { + @Override + public void run() { + @SuppressWarnings("unchecked") + T value = (T)list.getSelectedValue(); + if (value == null) { + result.setRejected(); + } + else { + result.setDone(value); + } + } + }). + createPopup().showInFocusCenter(); + } + }); + return result; + } } \ No newline at end of file diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/VmConnection.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/VmConnection.java index 7a6c17169e7f..6f7d14c65100 100644 --- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/VmConnection.java +++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/VmConnection.java @@ -24,7 +24,6 @@ public abstract class VmConnection implements Disposable, BrowserC protected volatile T vm; private final ActionCallback opened = new ActionCallback(); - private final AtomicBoolean closed = new AtomicBoolean(); public final Vm getVm() { diff --git a/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/io/JsonReaderEx.java b/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/io/JsonReaderEx.java index 7dad7854ca0d..eaf83b872be8 100644 --- a/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/io/JsonReaderEx.java +++ b/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/io/JsonReaderEx.java @@ -665,6 +665,15 @@ public final class JsonReaderEx implements Closeable { * Returns the next token, a {@link JsonToken#NAME property name}, and consumes it */ public String nextName() { + String result = nextNameOrNull(); + if (result == null) { + throw createParseError("Expected a name but was " + peek()); + } + return result; + } + + @Nullable + public String nextNameOrNull() { int p = peeked; if (p == PEEKED_NONE) { p = doPeek(); @@ -680,7 +689,10 @@ public final class JsonReaderEx implements Closeable { result = nextQuotedValue('"'); } else { - throw createParseError("Expected a name but was " + peek()); + if (p != PEEKED_END_OBJECT && p != PEEKED_END_ARRAY) { + throw createParseError("Expected a name but was " + peek()); + } + return null; } peeked = PEEKED_NONE; return result; @@ -713,6 +725,7 @@ public final class JsonReaderEx implements Closeable { return in.charAt(offset + index); } + @NotNull @Override public CharSequence subSequence(int start, int end) { if ((end - start) > length) { @@ -1153,6 +1166,7 @@ public final class JsonReaderEx implements Closeable { /** * Closes this JSON reader and the underlying {@link java.io.Reader}. */ + @Override public void close() { peeked = PEEKED_NONE; stack[0] = JsonScope.CLOSED; @@ -1180,11 +1194,7 @@ public final class JsonReaderEx implements Closeable { push(JsonScope.EMPTY_OBJECT); count++; } - else if (p == PEEKED_END_ARRAY) { - stackSize--; - count--; - } - else if (p == PEEKED_END_OBJECT) { + else if (p == PEEKED_END_ARRAY || p == PEEKED_END_OBJECT) { stackSize--; count--; } diff --git a/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/JsonParseMethod.java b/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/JsonParseMethod.java index 8016b9b59539..6e7d21dee963 100644 --- a/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/JsonParseMethod.java +++ b/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/JsonParseMethod.java @@ -1,7 +1,6 @@ // Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - package org.jetbrains.jsonProtocol; import java.lang.annotation.ElementType; diff --git a/platform/script-debugger/protocol/protocol-reader/protocol-reader.iml b/platform/script-debugger/protocol/protocol-reader/protocol-reader.iml index d809f8c5132e..f8259f8992b9 100644 --- a/platform/script-debugger/protocol/protocol-reader/protocol-reader.iml +++ b/platform/script-debugger/protocol/protocol-reader/protocol-reader.iml @@ -1,6 +1,6 @@ - + @@ -10,6 +10,6 @@ + - - + \ No newline at end of file diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/AbsentSubtypeAspect.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/AbsentSubtypeAspect.java deleted file mode 100644 index 4a3b18df1d0e..000000000000 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/AbsentSubtypeAspect.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.jetbrains.protocolReader; - -class AbsentSubtypeAspect extends SubtypeAspect { - - @Override - void writeGetSuperMethodJava(TextOutput out) { - } - - @Override - void writeSuperFieldJava(TextOutput out) { - } - - @Override - void writeSuperConstructorParamJava(TextOutput out) { - } - - @Override - void writeSuperConstructorInitialization(TextOutput out) { - } - - @Override - void writeParseMethod(String className, ClassScope scope, TextOutput out) { - } - - @Override - public void writeInstantiateCode(String className, TextOutput out) { - out.append("new ").append(className); - } -} diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/DynamicReader.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/DynamicReader.java index 3485c83e684f..bd4b5f332ada 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/DynamicReader.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/DynamicReader.java @@ -1,10 +1,11 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - package org.jetbrains.protocolReader; -import java.util.*; +import gnu.trove.THashMap; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; public class DynamicReader { final LinkedHashMap, TypeHandler> typeToTypeHandler; @@ -15,20 +16,20 @@ public class DynamicReader { root = new ReaderRoot<>(readerRootClass, typeToTypeHandler); } - public GeneratedCodeMap generateStaticReader(StringBuilder stringBuilder, String packageName, String className, - Collection basePackages) { - final GlobalScope globalScope = new GlobalScope(typeToTypeHandler.values(), basePackages); + @NotNull + public GeneratedCodeMap generateReader(StringBuilder stringBuilder, String packageName, String className, + Collection basePackages) { + GlobalScope globalScope = new GlobalScope(typeToTypeHandler.values(), basePackages); FileScope fileScope = globalScope.newFileScope(stringBuilder); - final TextOutput out = fileScope.getOutput(); + TextOutput out = fileScope.getOutput(); out.append("// Generated source"); out.newLine().append("package ").append(packageName).append(';'); out.newLine().newLine().append("import org.jetbrains.jsonProtocol.*;"); out.newLine().newLine().append("import static org.jetbrains.jsonProtocol.JsonReaders.*;"); out.newLine().newLine().append("public final class ").append(className).space(); - out.append(root.getType().isInterface() ? "implements" : "extends").space().append(root.getType().getCanonicalName()).openBlock( - false); + out.append(root.getType().isInterface() ? "implements" : "extends").space().append(root.getType().getCanonicalName()).openBlock(false); - final ClassScope rootClassScope = fileScope.newClassScope(); + ClassScope rootClassScope = fileScope.newClassScope(); root.writeStaticMethodJava(rootClassScope); for (TypeHandler typeHandler : typeToTypeHandler.values()) { @@ -37,27 +38,31 @@ public class DynamicReader { out.newLine(); } + boolean isFirst = true; for (TypeHandler typeHandler : globalScope.getTypeFactories()) { - String name = globalScope.getTypeImplShortName(typeHandler); + if (isFirst) { + isFirst = false; + } + else { + out.newLine(); + } + String originName = typeHandler.getTypeClass().getCanonicalName(); - out.newLine().append("static final class ").append(name).append(Util.TYPE_FACTORY_NAME_POSTFIX).append(" extends ObjectFactory<"); + out.newLine().append("private static final class ").append(globalScope.getTypeImplShortName(typeHandler)).append(Util.TYPE_FACTORY_NAME_POSTFIX).append(" extends ObjectFactory<"); out.append(originName).append('>').openBlock(); out.append("@Override").newLine().append("public ").append(originName).append(" read(").append(Util.JSON_READER_PARAMETER_DEF); out.append(')').openBlock(); out.append("return "); typeHandler.writeInstantiateCode(rootClassScope, out); - out.append('(').append(Util.READER_NAME).append(");").closeBlock(); + out.append('(').append(Util.READER_NAME).append(", null);").closeBlock(); out.closeBlock(); - out.newLine(); } out.closeBlock(); - Map, String> typeToImplClassName = new HashMap<>(); + Map, String> typeToImplClassName = new THashMap<>(); for (TypeHandler typeHandler : typeToTypeHandler.values()) { - String shortName = fileScope.getTypeImplShortName(typeHandler); - String fullReference = packageName + "." + className + "." + shortName; - typeToImplClassName.put(typeHandler.getTypeClass(), fullReference); + typeToImplClassName.put(typeHandler.getTypeClass(), packageName + "." + className + "." + fileScope.getTypeImplShortName(typeHandler)); } return new GeneratedCodeMap(typeToImplClassName); diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ExistingSubtypeAspect.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ExistingSubtypeAspect.java index 4e79fb71498d..326d3f9a1c81 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ExistingSubtypeAspect.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ExistingSubtypeAspect.java @@ -1,6 +1,6 @@ package org.jetbrains.protocolReader; -class ExistingSubtypeAspect extends SubtypeAspect { +class ExistingSubtypeAspect { private SubtypeCaster subtypeCaster; private final TypeRef jsonSuperClass; @@ -12,28 +12,23 @@ class ExistingSubtypeAspect extends SubtypeAspect { this.subtypeCaster = subtypeCaster; } - @Override void writeGetSuperMethodJava(TextOutput out) { out.newLine().append("@Override").newLine().append("public ").append(jsonSuperClass.get().getTypeClass().getCanonicalName() ).append(" getSuper()").openBlock(); out.append("return ").append(Util.BASE_VALUE_PREFIX).semi().closeBlock(); } - @Override void writeSuperFieldJava(TextOutput out) { out.newLine().append("private final ").append(jsonSuperClass.get().getTypeClass().getCanonicalName()).append(' ').append(Util.BASE_VALUE_PREFIX).semi().newLine(); } - @Override void writeSuperConstructorParamJava(TextOutput out) { out.comma().append(jsonSuperClass.get().getTypeClass().getCanonicalName()).append(' ').append(Util.BASE_VALUE_PREFIX); } - @Override void writeSuperConstructorInitialization(TextOutput out) { out.append("this.").append(Util.BASE_VALUE_PREFIX).append(" = ").append(Util.BASE_VALUE_PREFIX).append(';').newLine().newLine(); } - @Override void writeParseMethod(String className, ClassScope scope, TextOutput out) { out.newLine().append("public static ").append(className).space().append("parse").append("(").append(Util.JSON_READER_PARAMETER_DEF).append(')').openBlock(); out.append("return "); @@ -44,7 +39,6 @@ class ExistingSubtypeAspect extends SubtypeAspect { out.newLine(); } - @Override public void writeInstantiateCode(String className, TextOutput out) { out.append(className).append(".parse"); } diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/FieldProcessor.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/FieldProcessor.java index 111e58caa3a6..77a91e8543d1 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/FieldProcessor.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/FieldProcessor.java @@ -1,5 +1,6 @@ package org.jetbrains.protocolReader; +import org.jetbrains.annotations.NotNull; import org.jetbrains.jsonProtocol.JsonField; import org.jetbrains.jsonProtocol.JsonNullable; import org.jetbrains.jsonProtocol.JsonOptionalField; @@ -28,7 +29,7 @@ class FieldProcessor { // todo sort by source location Arrays.sort(methods, new Comparator() { @Override - public int compare(Method o1, Method o2) { + public int compare(@NotNull Method o1, @NotNull Method o2) { return o1.getName().compareTo(o2.getName()); } }); @@ -120,20 +121,10 @@ class FieldProcessor { int position = volatileFields.size(); FieldTypeInfo fieldTypeInfo; if (internalType) { - fieldTypeInfo = new FieldTypeInfo() { - @Override - public void appendValueTypeNameJava(FileScope scope, TextOutput out) { - fieldTypeParser.appendInternalValueTypeName(scope, out); - } - }; + fieldTypeInfo = fieldTypeParser::appendInternalValueTypeName; } else { - fieldTypeInfo = new FieldTypeInfo() { - @Override - public void appendValueTypeNameJava(FileScope scope, TextOutput out) { - fieldTypeParser.appendFinishedValueTypeName(out); - } - }; + fieldTypeInfo = (scope, out) -> fieldTypeParser.appendFinishedValueTypeName(out); } VolatileFieldBinding binding = new VolatileFieldBinding(position, fieldTypeInfo); volatileFields.add(binding); diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/GlobalScope.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/GlobalScope.java index 6a31b5ad59c0..9866d7b71d01 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/GlobalScope.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/GlobalScope.java @@ -2,6 +2,7 @@ package org.jetbrains.protocolReader; import gnu.trove.THashMap; import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; import java.util.*; @@ -84,7 +85,7 @@ public class GlobalScope { // Sort to produce consistent GeneratedCodeMap later. Collections.sort(list, new Comparator>() { @Override - public int compare(TypeHandler o1, TypeHandler o2) { + public int compare(@NotNull TypeHandler o1, @NotNull TypeHandler o2) { return getName(o1).compareTo(getName(o2)); } diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/InterfaceReader.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/InterfaceReader.java index cc4e2566f4dd..a02b4ae8f18a 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/InterfaceReader.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/InterfaceReader.java @@ -117,7 +117,10 @@ class InterfaceReader { } for (SubtypeCaster subtypeCaster : subtypeCasters) { - subtypeCaster.getSubtypeHandler().getSubtypeSupport().setSubtypeCaster(subtypeCaster); + ExistingSubtypeAspect subtypeSupport = subtypeCaster.getSubtypeHandler().getSubtypeSupport(); + if (subtypeSupport != null) { + subtypeSupport.setSubtypeCaster(subtypeCaster); + } } return typeToTypeHandler; diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/MethodHandler.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/MethodHandler.java index adf5ac6f7ddf..a877b654c020 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/MethodHandler.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/MethodHandler.java @@ -4,19 +4,22 @@ package org.jetbrains.protocolReader; +import org.jetbrains.annotations.NotNull; + import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.Collections; -import java.util.Iterator; +import java.util.List; abstract class MethodHandler { abstract void writeMethodImplementationJava(ClassScope classScope, Method m, TextOutput out); - protected static void appendMethodSignatureJava(Method m, Iterable paramNames, TextOutput out) { + protected static void appendMethodSignatureJava(@NotNull Method m, @NotNull List paramNames, @NotNull TextOutput out) { out.append(m.getName()).append('('); boolean firstArg = true; - Iterator namesIt = paramNames.iterator(); - for (Type arg : m.getGenericParameterTypes()) { + Type[] types = m.getGenericParameterTypes(); + for (int i = 0, length = types.length; i < length; i++) { + Type arg = types[i]; if (firstArg) { firstArg = false; } @@ -24,7 +27,7 @@ abstract class MethodHandler { out.comma(); } Util.writeJavaTypeName(arg, out); - out.append(' ').append(namesIt.next()); + out.space().append(paramNames.get(i)); } out.append(')'); } @@ -33,10 +36,10 @@ abstract class MethodHandler { writeMethodDeclarationJava(out, m, Collections.emptyList()); } - protected static void writeMethodDeclarationJava(TextOutput out, Method m, Iterable paramNames) { + protected static void writeMethodDeclarationJava(@NotNull TextOutput out, @NotNull Method m, @NotNull List paramNames) { out.append("@Override").newLine().append("public "); Util.writeJavaTypeName(m.getGenericReturnType(), out); - out.append(' '); + out.space(); appendMethodSignatureJava(m, paramNames, out); } } diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ObjectValueReader.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ObjectValueReader.java index 025fb525c367..d6e4275ae0e3 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ObjectValueReader.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ObjectValueReader.java @@ -43,7 +43,7 @@ class ObjectValueReader extends ValueReader { refToType.get().writeInstantiateCode(scope.getRootClassScope(), subtyping, out); out.append('('); addReaderParameter(subtyping, out); - if (subtyping && refToType.get().getSubtypeSupport() instanceof ExistingSubtypeAspect) { + if (subtyping && refToType.get().getSubtypeSupport() != null) { out.comma().append("this"); } out.append(')'); diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReadDelegate.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReadDelegate.java index fade272204a5..56dcc310fa83 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReadDelegate.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReadDelegate.java @@ -1,22 +1,30 @@ package org.jetbrains.protocolReader; +import org.jetbrains.annotations.NotNull; + import java.lang.reflect.Method; +import java.util.Arrays; import java.util.Collections; import java.util.List; class ReadDelegate { private static final List STATIC_METHOD_PARAM_NAME_LIST = Collections.singletonList(Util.READER_NAME); + private static final List STATIC_METHOD_PARAM_NAME_LIST2 = Arrays.asList(Util.READER_NAME, "nextName"); private final TypeHandler typeHandler; private final boolean isList; - ReadDelegate(TypeHandler typeHandler, boolean isList) { + private final List paramNames; + + ReadDelegate(@NotNull TypeHandler typeHandler, boolean isList, boolean hasNextNameParam) { this.typeHandler = typeHandler; this.isList = isList; + + paramNames = hasNextNameParam ? STATIC_METHOD_PARAM_NAME_LIST2 : STATIC_METHOD_PARAM_NAME_LIST; } void write(ClassScope scope, Method method, TextOutput out) { - MethodHandler.writeMethodDeclarationJava(out, method, STATIC_METHOD_PARAM_NAME_LIST); + MethodHandler.writeMethodDeclarationJava(out, method, paramNames); out.openBlock(); out.append("return "); if (isList) { @@ -24,7 +32,10 @@ class ReadDelegate { } else { typeHandler.writeInstantiateCode(scope, out); - out.append("(").append(Util.READER_NAME).append(')'); + out.append('(').append(Util.READER_NAME); + out.comma().space(); + out.append(paramNames.size() == 1 ? "null" : "nextName"); + out.append(')'); } out.semi(); diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderGenerator.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderGenerator.java index 6988139a5bcb..8299afe91ece 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderGenerator.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderGenerator.java @@ -18,7 +18,7 @@ public class ReaderGenerator { configuration.getPackageName().replace('.', File.separatorChar), configuration.getClassName() + ".java")); - generateImpl(configuration, fileUpdater.builder); + generate(configuration, fileUpdater.builder); fileUpdater.update(); } @@ -96,12 +96,7 @@ public class ReaderGenerator { } } - return new Params() { - @Override - public String outputDirectory() { - return outputDirParam.getValue(); - } - }; + return outputDirParam::getValue; } private interface ParamListener { @@ -128,12 +123,12 @@ public class ReaderGenerator { } protected static GeneratedCodeMap buildParserMap(GenerateConfiguration configuration) { - return generateImpl(configuration, new StringBuilder()); + return generate(configuration, new StringBuilder()); } - private static GeneratedCodeMap generateImpl(GenerateConfiguration configuration, StringBuilder stringBuilder) { - return configuration.getParser().generateStaticReader(stringBuilder, - configuration.getPackageName(), configuration.getClassName(), - configuration.getBasePackagesMap()); + private static GeneratedCodeMap generate(GenerateConfiguration configuration, StringBuilder stringBuilder) { + return configuration.getParser().generateReader(stringBuilder, + configuration.getPackageName(), configuration.getClassName(), + configuration.getBasePackagesMap()); } } diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderRoot.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderRoot.java index 7914a5103ac6..f7ce9eb9eb39 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderRoot.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderRoot.java @@ -1,7 +1,8 @@ package org.jetbrains.protocolReader; -import org.jetbrains.io.JsonReaderEx; import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.io.JsonReaderEx; import org.jetbrains.jsonProtocol.JsonParseMethod; import java.lang.reflect.Method; @@ -32,7 +33,7 @@ class ReaderRoot { Method[] methods = clazz.getMethods(); Arrays.sort(methods, new Comparator() { @Override - public int compare(Method o1, Method o2) { + public int compare(@NotNull Method o1, @NotNull Method o2) { return o1.getName().compareTo(o2.getName()); } }); @@ -68,12 +69,12 @@ class ReaderRoot { } Type[] arguments = m.getGenericParameterTypes(); - if (arguments.length != 1) { + if (arguments.length > 2) { throw new JsonProtocolModelParseException("Exactly one argument is expected in " + m); } Type argument = arguments[0]; if (argument == JsonReaderEx.class || argument == Object.class) { - methodMap.put(m, new ReadDelegate(typeHandler, isList)); + methodMap.put(m, new ReadDelegate(typeHandler, isList, arguments.length != 1)); } else { throw new JsonProtocolModelParseException("Unrecognized argument type in " + m); diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/SubtypeAspect.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/SubtypeAspect.java deleted file mode 100644 index 9af37de01e55..000000000000 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/SubtypeAspect.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.jetbrains.protocolReader; - -/** - * Encapsulate subtype aspects of the type. - */ -abstract class SubtypeAspect { - abstract void writeSuperFieldJava(TextOutput out); - abstract void writeSuperConstructorParamJava(TextOutput out); - abstract void writeSuperConstructorInitialization(TextOutput out); - - abstract void writeParseMethod(String className, ClassScope scope, TextOutput out); - - public abstract void writeInstantiateCode(String className, TextOutput out); - - abstract void writeGetSuperMethodJava(TextOutput out); - - public void setSubtypeCaster(SubtypeCaster subtypeCaster) { - } -} \ No newline at end of file diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/TypeHandler.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/TypeHandler.java index 401fbcff79d0..a2aaf4424429 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/TypeHandler.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/TypeHandler.java @@ -1,9 +1,7 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - package org.jetbrains.protocolReader; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jsonProtocol.JsonObjectBased; import java.lang.reflect.Method; @@ -16,14 +14,13 @@ class TypeHandler { private final List volatileFields; - /** Method implementation for dynamic proxy. */ private final LinkedHashMap methodHandlerMap; /** Loaders that should read values and save them in field array on parse time. */ private final List fieldLoaders; /** Subtype aspects of the type or null */ - private final SubtypeAspect subtypeAspect; + private final ExistingSubtypeAspect subtypeAspect; private final boolean hasLazyFields; @@ -37,29 +34,25 @@ class TypeHandler { this.methodHandlerMap = methodHandlerMap; this.fieldLoaders = fieldLoaders; this.hasLazyFields = hasLazyFields; - if (jsonSuperClass == null) { - subtypeAspect = new AbsentSubtypeAspect(); - } - else { - subtypeAspect = new ExistingSubtypeAspect(jsonSuperClass); - } + subtypeAspect = jsonSuperClass == null ? null : new ExistingSubtypeAspect(jsonSuperClass); } public Class getTypeClass() { return typeClass; } - public SubtypeAspect getSubtypeSupport() { + @Nullable + public ExistingSubtypeAspect getSubtypeSupport() { return subtypeAspect; } - public void writeInstantiateCode(ClassScope scope, TextOutput out) { + public void writeInstantiateCode(@NotNull ClassScope scope, @NotNull TextOutput out) { writeInstantiateCode(scope, false, out); } - public void writeInstantiateCode(ClassScope scope, boolean deferredReading, TextOutput out) { + public void writeInstantiateCode(@NotNull ClassScope scope, boolean deferredReading, @NotNull TextOutput out) { String className = scope.getTypeImplReference(this); - if (deferredReading) { + if (deferredReading || subtypeAspect == null) { out.append("new ").append(className); } else { @@ -67,10 +60,10 @@ class TypeHandler { } } - public void writeStaticClassJava(FileScope fileScope) { + public void writeStaticClassJava(@NotNull FileScope fileScope) { TextOutput out = fileScope.getOutput(); String valueImplClassName = fileScope.getTypeImplShortName(this); - out.append("public static final class ").append(valueImplClassName); + out.append("private static final class ").append(valueImplClassName); out.append(" implements ").append(getTypeClass().getCanonicalName()).openBlock(); @@ -89,12 +82,16 @@ class TypeHandler { out.newLine(); } - subtypeAspect.writeSuperFieldJava(out); + if (subtypeAspect != null) { + subtypeAspect.writeSuperFieldJava(out); + } writeConstructorMethod(valueImplClassName, classScope, out); out.newLine(); - subtypeAspect.writeParseMethod(valueImplClassName, classScope, out); + if (subtypeAspect != null) { + subtypeAspect.writeParseMethod(valueImplClassName, classScope, out); + } for (Map.Entry en : methodHandlerMap.entrySet()) { out.newLine(); @@ -103,7 +100,9 @@ class TypeHandler { } writeBaseMethods(out); - subtypeAspect.writeGetSuperMethodJava(out); + if (subtypeAspect != null) { + subtypeAspect.writeGetSuperMethodJava(out); + } out.indentOut().append('}'); } @@ -132,27 +131,47 @@ class TypeHandler { out.closeBlock(); } - private void writeConstructorMethod(String valueImplClassName, ClassScope classScope, TextOutput out) { - out.newLine().append("public ").append(valueImplClassName).append("(").append(Util.JSON_READER_PARAMETER_DEF); - subtypeAspect.writeSuperConstructorParamJava(out); + private void writeConstructorMethod(@NotNull String valueImplClassName, @NotNull ClassScope classScope, @NotNull TextOutput out) { + out.newLine().append(valueImplClassName).append('(').append(Util.JSON_READER_PARAMETER_DEF).comma().append("String name"); + if (subtypeAspect != null) { + subtypeAspect.writeSuperConstructorParamJava(out); + } out.append(')').openBlock(); - subtypeAspect.writeSuperConstructorInitialization(out); + if (subtypeAspect != null) { + subtypeAspect.writeSuperConstructorInitialization(out); + } if (JsonObjectBased.class.isAssignableFrom(typeClass) || hasLazyFields) { - out.append(Util.PENDING_INPUT_READER_NAME).append(" = ").append(Util.READER_NAME).append(".subReader();").newLine(); + out.append(Util.PENDING_INPUT_READER_NAME).append(" = ").append(Util.READER_NAME).append(".subReader()").semi().newLine(); } if (fieldLoaders.isEmpty()) { out.append(Util.READER_NAME).append(".skipValue()").semi(); } else { - out.append(Util.READER_NAME).append(".beginObject();"); + out.append("if (name == null)").openBlock(); + { + out.append("reader.beginObject()").semi(); + out.newLine().append("if (reader.hasNext())").openBlock(); + { + out.append("name = reader.nextName()").semi(); + } + out.closeBlock(); + out.newLine().append("else").openBlock(); + { + out.append("return").semi(); + } + out.closeBlock(); + } + out.closeBlock(); + out.newLine(); + writeReadFields(out, classScope); // we don't read all data if we have lazy fields, so, we should not check end of stream //if (!hasLazyFields) { - out.newLine().append(Util.READER_NAME).append(".endObject();"); + out.newLine().newLine().append(Util.READER_NAME).append(".endObject()").semi(); //} } out.closeBlock(); @@ -166,16 +185,16 @@ class TypeHandler { out.newLine().append("int i = 0").semi(); } - out.newLine().append("while (reader.hasNext())").openBlock(!hasOnlyOneFieldLoader); - if (!hasOnlyOneFieldLoader) { - out.append("CharSequence name = reader.nextNameAsCharSequence();"); - } - + out.newLine().append("do").openBlock(); boolean isFirst = true; String operator = "if"; for (FieldLoader fieldLoader : fieldLoaders) { + if (!isFirst) { + out.newLine(); + } + String fieldName = fieldLoader.getFieldName(); - out.newLine().append(operator).append(" (").append(hasOnlyOneFieldLoader ? "reader.nextName()" : "name"); + out.append(operator).append(" (").append(hasOnlyOneFieldLoader ? "reader.nextName()" : "name"); out.append(".equals(\"").append(fieldName).append("\"))").openBlock(); { assignField(out, fieldName); @@ -204,6 +223,7 @@ class TypeHandler { out.newLine().append("else").openBlock().append("i++").semi().closeBlock(); } out.closeBlock(); + out.newLine().append("while ((name = reader.nextNameOrNull()) != null)").semi(); } private static TextOutput assignField(TextOutput out, String fieldName) { diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/Util.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/Util.java index 105cd6665b2e..13c7fd1c39e0 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/Util.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/Util.java @@ -1,5 +1,7 @@ package org.jetbrains.protocolReader; +import org.jetbrains.annotations.NotNull; + import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.WildcardType; @@ -14,12 +16,12 @@ public class Util { public static final String BASE_VALUE_PREFIX = "baseMessage"; public static final String JSON_READER_CLASS_NAME = "org.jetbrains.io.JsonReaderEx"; - public static final String JSON_READER_PARAMETER_DEF = JSON_READER_CLASS_NAME + " " + READER_NAME; + public static final String JSON_READER_PARAMETER_DEF = JSON_READER_CLASS_NAME + ' ' + READER_NAME; /** * Generate Java type name of the passed type. Type may be parameterized. */ - public static void writeJavaTypeName(Type arg, TextOutput out) { + public static void writeJavaTypeName(@NotNull Type arg, @NotNull TextOutput out) { if (arg instanceof Class) { out.append(((Class)arg).getCanonicalName()); } diff --git a/platform/usageView/src/com/intellij/usages/ChunkExtractor.java b/platform/usageView/src/com/intellij/usages/ChunkExtractor.java index b9db68c69ce3..ceba6f18df09 100644 --- a/platform/usageView/src/com/intellij/usages/ChunkExtractor.java +++ b/platform/usageView/src/com/intellij/usages/ChunkExtractor.java @@ -282,6 +282,7 @@ public class ChunkExtractor { ) { return true; } + if (key == null) continue; final TextAttributesKey fallbackAttributeKey = key.getFallbackAttributeKey(); if (fallbackAttributeKey != null && isHighlightedAsComment(fallbackAttributeKey)) { return true; @@ -295,6 +296,7 @@ public class ChunkExtractor { if (key == DefaultLanguageHighlighterColors.STRING || key == SyntaxHighlighterColors.STRING) { return true; } + if (key == null) continue; final TextAttributesKey fallbackAttributeKey = key.getFallbackAttributeKey(); if (fallbackAttributeKey != null && isHighlightedAsString(fallbackAttributeKey)) { return true; diff --git a/platform/usageView/src/com/intellij/usages/UsageViewSettings.java b/platform/usageView/src/com/intellij/usages/UsageViewSettings.java index 8312c330b987..136d95038c24 100644 --- a/platform/usageView/src/com/intellij/usages/UsageViewSettings.java +++ b/platform/usageView/src/com/intellij/usages/UsageViewSettings.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -25,9 +25,10 @@ import java.io.File; @State( name = "UsageViewSettings", storages = { - @Storage( - file = StoragePathMacros.APP_CONFIG + "/other.xml" - )} + @Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml"), + @Storage(file = StoragePathMacros.APP_CONFIG + "/usageView.xml") + }, + storageChooser = LastStorageChooserForWrite.class ) public class UsageViewSettings implements PersistentStateComponent { @NonNls public String EXPORT_FILE_NAME = "report.txt"; diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index bef1c10517d7..ead4ca8869bf 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -281,6 +281,9 @@ ide.dfa.time.limit.online.description=Time limit (in milliseconds) that is allow ide.dfa.time.limit.offline=5000 ide.dfa.time.limit.offline.description=Time limit (in milliseconds) that is allowed to analyze data flow for one method in Analyze | Inspect Code... +idea.dfa.live.variables.analysis=true +idea.dfa.live.variables.analysis.description=Whether to flush dead variables when they're not needed when performing data flow analysis + ide.ignore.call.result.inspection.honor.inferred.pure=false ide.ignore.call.result.inspection.honor.inferred.pure.description=Whether inferred @Contract(pure=true) annotations should be taken into account in ''Result of method call ignored'' inspection @@ -353,7 +356,6 @@ search.everywhere.configurations=true search.everywhere.settings=false svn.use.incoming.optimization=false -svn.executable.locale=C.UTF-8 svn.lowest.supported.format.for.command.line=1.7.0 svn.use.svnkit.for.https.server.certificate.check=true diff --git a/platform/util/src/com/intellij/icons/AllIcons.java b/platform/util/src/com/intellij/icons/AllIcons.java index dcbb1c880493..f1336fe1bedc 100644 --- a/platform/util/src/com/intellij/icons/AllIcons.java +++ b/platform/util/src/com/intellij/icons/AllIcons.java @@ -378,6 +378,7 @@ public class AllIcons { public static final Icon CollapseAllHover = IconLoader.getIcon("/general/collapseAllHover.png"); // 11x16 public static final Icon Combo = IconLoader.getIcon("/general/combo.png"); // 16x16 public static final Icon Combo2 = IconLoader.getIcon("/general/combo2.png"); // 16x16 + public static final Icon Combo3 = IconLoader.getIcon("/general/combo3.png"); // 16x16 public static final Icon ComboArrow = IconLoader.getIcon("/general/comboArrow.png"); // 16x16 public static final Icon ComboArrowDown = IconLoader.getIcon("/general/comboArrowDown.png"); // 9x5 public static final Icon ComboArrowLeft = IconLoader.getIcon("/general/comboArrowLeft.png"); // 5x9 diff --git a/platform/util/src/com/intellij/openapi/util/Version.java b/platform/util/src/com/intellij/openapi/util/Version.java index afcd6eaaecf7..638d3100d7b6 100644 --- a/platform/util/src/com/intellij/openapi/util/Version.java +++ b/platform/util/src/com/intellij/openapi/util/Version.java @@ -1,8 +1,9 @@ package com.intellij.openapi.util; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class Version { +public class Version implements Comparable { public final int major; public final int minor; public final int bugfix; @@ -49,6 +50,10 @@ public class Version { return compareTo(major, minor, bugfix) < 0; } + public int compareTo(@NotNull Version version) { + return compareTo(version.major, version.minor, version.bugfix); + } + public int compareTo(@Nullable Integer major) { return compareTo(major, null); } diff --git a/platform/util/src/com/intellij/util/text/ImmutableText.java b/platform/util/src/com/intellij/util/text/ImmutableText.java index 4ec4b93ec2b2..2dde3eb60293 100644 --- a/platform/util/src/com/intellij/util/text/ImmutableText.java +++ b/platform/util/src/com/intellij/util/text/ImmutableText.java @@ -96,7 +96,14 @@ public final class ImmutableText extends ImmutableCharSequence implements CharAr return new ImmutableText(new LeafNode(chars)); } - private ImmutableText ensureChunked() { + /** + * When first loaded, ImmutableText contents are stored as a single large array. This saves memory but isn't + * modification-friendly as it disallows slightly changed texts to retain most of the internal structure of the + * original document. Whoever retains old non-chunked version will use more memory than really needed. + * + * @return a copy of this text better prepared for small modifications to fully enable structure-sharing capabilities + */ + public ImmutableText ensureChunked() { if (length() > BLOCK_SIZE && myNode instanceof LeafNode) { return new ImmutableText(nodeOf(((LeafNode)myNode)._data, 0, length())); } @@ -292,7 +299,7 @@ public final class ImmutableText extends ImmutableCharSequence implements CharAr * @throws IndexOutOfBoundsException if (start < 0) || (end < 0) || * (start > end) || (end > this.length()) */ - private ImmutableText subtext(int start, int end) { + public ImmutableText subtext(int start, int end) { if ((start < 0) || (start > end) || (end > length())) throw new IndexOutOfBoundsException(); if ((start == 0) && (end == length())) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java index 47b9375a7369..5abaaf2da696 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java @@ -8,7 +8,6 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Function; -import com.intellij.util.NotNullFunction; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.DateFormatUtil; import com.intellij.vcs.log.*; @@ -75,24 +74,32 @@ public class GraphTableModel extends AbstractTableModel { List> commits = myDataPack.getPermanentGraph().getAllCommits(); for (int i = 0; i < 100 && i < commits.size(); i++) { GraphCommit commit = commits.get(i); - sb.append(myDataHolder.getHash(commit.getId()) + "\n"); + sb.append(String.format("%s -> %s\n", myDataHolder.getHash(commit.getId()).toShortString(), getParents(commit))); } sb.append("\nALL REFS:\n"); - printRefs(sb, myDataHolder.getHashMap().asIndexGetter(), myDataPack.getRefsModel().getAllRefsByRoot()); + printRefs(sb, myDataPack.getRefsModel().getAllRefsByRoot()); return sb.toString(); } - private static void printRefs(@NotNull StringBuilder sb, - @NotNull final NotNullFunction indexGetter, - @NotNull Map> refs) { + @NotNull + private String getParents(@NotNull GraphCommit commit) { + return StringUtil.join(commit.getParents(), new Function() { + @Override + public String fun(Integer integer) { + return myDataHolder.getHash(integer).toShortString(); + } + }, ", "); + } + + private static void printRefs(@NotNull StringBuilder sb, @NotNull Map> refs) { for (Map.Entry> entry : refs.entrySet()) { - sb.append(entry.getKey().getName() + ":\n"); + sb.append("\n\n" + entry.getKey().getName() + ":\n"); sb.append(StringUtil.join(entry.getValue(), new Function() { @Override public String fun(@NotNull VcsRef ref) { - return ref.getName() + "(" + indexGetter.fun(ref.getCommitHash()) + ")"; + return ref.getName() + " : " + ref.getCommitHash().toShortString(); } - }, ",")); + }, "\n")); } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java index 4fb2b75c13a0..77e154a329c2 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java @@ -121,6 +121,7 @@ public class XFramesView extends XDebugView { XDebugSession session = getSession(e); if (session != null) { mySelectedFrameIndex = 0; + myRefresh = false; updateFrames((XExecutionStack)item, session); } } @@ -305,7 +306,7 @@ public class XFramesView extends XDebugView { Object selected = myFramesList.getSelectedValue(); if (selected instanceof XStackFrame) { if (session != null) { - if (force || !myRefresh) { + if (force || (!myRefresh && session.getCurrentStackFrame() != selected)) { session.setCurrentStackFrame(mySelectedStack, (XStackFrame)selected, mySelectedFrameIndex == 0); } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/BreakpointEditor.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/BreakpointEditor.java index 5c14020f603f..79c8dc49c398 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/BreakpointEditor.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/BreakpointEditor.java @@ -90,10 +90,6 @@ public class BreakpointEditor { } public void actionPerformed(AnActionEvent e) { - Component component = PlatformDataKeys.CONTEXT_COMPONENT.getData(e.getDataContext()); - if (component instanceof JComboBox && SwingUtilities.isDescendingFrom(component, getMainPanel())) { - ((JComboBox)component).hidePopup(); - } done(); } }; diff --git a/plugins/devkit/src/util/ExtensionPointLocator.java b/plugins/devkit/src/util/ExtensionPointLocator.java index c4a5b19c156a..e8d895a1e7dc 100644 --- a/plugins/devkit/src/util/ExtensionPointLocator.java +++ b/plugins/devkit/src/util/ExtensionPointLocator.java @@ -75,7 +75,7 @@ public class ExtensionPointLocator { } final Project project = psiClass.getProject(); - final Collection candidates = DomService.getInstance().getDomFileCandidates(IdeaPlugin.class, project); + final Collection candidates = DomService.getInstance().getDomFileCandidates(IdeaPlugin.class, project, GlobalSearchScope.allScope(project)); GlobalSearchScope scope = GlobalSearchScope.filesScope(project, candidates); PsiSearchHelper.SERVICE.getInstance(project).processUsagesInNonJavaFiles(name, new PsiNonJavaFileReferenceProcessor() { @Override diff --git a/plugins/git4idea/src/git4idea/push/GitPushTargetPanel.java b/plugins/git4idea/src/git4idea/push/GitPushTargetPanel.java index 40eaf69b9f7b..aa03697963c8 100644 --- a/plugins/git4idea/src/git4idea/push/GitPushTargetPanel.java +++ b/plugins/git4idea/src/git4idea/push/GitPushTargetPanel.java @@ -182,7 +182,7 @@ class GitPushTargetPanel extends PushTargetPanel { @Override public void fireOnChange() { - if (myError == null) { + if (myError != null) { return; } String remoteName = myRemoteLabel.getText(); diff --git a/plugins/groovy/jetgroovy.iml b/plugins/groovy/jetgroovy.iml index 4ae317b2555c..c06341abadd7 100644 --- a/plugins/groovy/jetgroovy.iml +++ b/plugins/groovy/jetgroovy.iml @@ -37,6 +37,6 @@ + - - + \ No newline at end of file diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index ea356d13e917..6d171987ccd5 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -598,6 +598,9 @@ + + = 0; + } + } + return false; + } +} diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java index 44c58f04e196..13658580fe4e 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java @@ -82,6 +82,7 @@ public class ControlFlowGraph implements CodeConstants { } public String toString() { + if (blocks == null) return "Empty"; String new_line_separator = DecompilerContext.getNewLineSeparator(); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenJUnitPatcher.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenJUnitPatcher.java index 7636a02fe98b..3249bd48ac32 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenJUnitPatcher.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenJUnitPatcher.java @@ -17,9 +17,12 @@ package org.jetbrains.idea.maven.execution; import com.intellij.execution.JUnitPatcher; import com.intellij.execution.configurations.JavaParameters; +import com.intellij.execution.configurations.ParametersList; import com.intellij.openapi.module.Module; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.containers.ContainerUtil; 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; @@ -31,11 +34,15 @@ import org.jetbrains.idea.maven.project.MavenTestRunningSettings; import org.jetbrains.idea.maven.utils.MavenJDOMUtil; import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * @author Sergey Evdokimov */ public class MavenJUnitPatcher extends JUnitPatcher { + public static final Pattern PROPERTY_PATTERN = Pattern.compile("\\$\\{(.+?)\\}"); @Override public void patchJavaParameters(@Nullable Module module, JavaParameters javaParameters) { @@ -71,6 +78,7 @@ public class MavenJUnitPatcher extends JUnitPatcher { if (!javaParameters.getVMParametersList().hasProperty(propertyName)) { String value = resolveSurefireProperties(element.getValue()); + value = resolveVmProperties(javaParameters.getVMParametersList(), value); if (isResolved(value)) { javaParameters.getVMParametersList().addProperty(propertyName, value); } @@ -87,6 +95,7 @@ public class MavenJUnitPatcher extends JUnitPatcher { if (!javaParameters.getEnv().containsKey(variableName)) { String value = resolveSurefireProperties(element.getValue()); + value = resolveVmProperties(javaParameters.getVMParametersList(), value); if (isResolved(value)) { javaParameters.addEnv(variableName, value); } @@ -99,6 +108,7 @@ public class MavenJUnitPatcher extends JUnitPatcher { Element argLine = config.getChild("argLine"); if (argLine != null) { String value = resolveSurefireProperties(argLine.getTextTrim()); + value = resolveVmProperties(javaParameters.getVMParametersList(), value); if (StringUtil.isNotEmpty(value) && isResolved(value)) { javaParameters.getVMParametersList().addParametersString(value); } @@ -110,6 +120,22 @@ public class MavenJUnitPatcher extends JUnitPatcher { return value.replaceAll("\\$\\{surefire\\.(forkNumber|threadNumber)\\}", "1"); } + private static String resolveVmProperties(@NotNull ParametersList vmParameters, @NotNull String value) { + Matcher matcher = PROPERTY_PATTERN.matcher(value); + Map toReplace = ContainerUtil.newHashMap(); + while (matcher.find()) { + String finding = matcher.group(); + final String propertyValue = vmParameters.getPropertyValue(finding.substring(2, finding.length() - 1)); + if(propertyValue == null) continue; + toReplace.put(finding, propertyValue); + } + for (Map.Entry entry : toReplace.entrySet()) { + value = value.replace(entry.getKey(), entry.getValue()); + } + + return value; + } + private static boolean isEnabled(String s) { return !Boolean.valueOf(System.getProperty("idea.maven.surefire.disable." + s)); } diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/execution/MavenJUnitPatcherTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/execution/MavenJUnitPatcherTest.java index d2166e9383a7..4d285412a00c 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/execution/MavenJUnitPatcherTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/execution/MavenJUnitPatcherTest.java @@ -64,4 +64,37 @@ public class MavenJUnitPatcherTest extends MavenImportingTestCase { assertEquals(asList("-Xmx2048M", "-XX:MaxPermSize=512M", "-Dargs=can have spaces"), javaParameters.getVMParametersList().getList()); } + + public void testVmPropertiesResolve() throws Exception { + VirtualFile m1 = createModulePom("m1", "test" + + "m1" + + "1" + + "" + + " " + + " test" + + " m2" + + " 1" + + " " + + "" + + "" + + " " + + " org.apache.maven.plugins" + + " maven-surefire-plugin" + + " 2.16" + + " " + + " -Xmx2048M -XX:MaxPermSize=512M \"-Dargs=can have spaces\" ${argLineApx}" + + " " + + " " + + ""); + + importProjects(m1); + Module module = getModule("m1"); + + MavenJUnitPatcher mavenJUnitPatcher = new MavenJUnitPatcher(); + JavaParameters javaParameters = new JavaParameters(); + javaParameters.getVMParametersList().addProperty("argLineApx", "-DsomeKey=someValue"); + mavenJUnitPatcher.patchJavaParameters(module, javaParameters); + assertEquals(asList("-DargLineApx=-DsomeKey=someValue", "-Xmx2048M", "-XX:MaxPermSize=512M", "-Dargs=can have spaces", "-DsomeKey=someValue"), + javaParameters.getVMParametersList().getList()); + } } diff --git a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesUtil.java b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesUtil.java index 0867b6b5faa1..ac673f634791 100644 --- a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesUtil.java +++ b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesUtil.java @@ -80,6 +80,11 @@ public class PropertiesUtil { @NotNull public static String getDefaultBaseName(@NotNull final VirtualFile file) { final String name = file.getName(); + + if (!StringUtil.containsChar(name, '_')) { + return FileUtil.getNameWithoutExtension(name); + } + final Matcher matcher = LOCALE_PATTERN.matcher(name); final String baseNameWithExtension; if (matcher.find()) { diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleManager.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleManager.java index a01c123f8763..9e2e8e477d64 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleManager.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleManager.java @@ -20,7 +20,10 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.openapi.util.NullableComputable; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.util.Function; @@ -64,18 +67,31 @@ public class ResourceBundleManager implements PersistentStateComponent> oldAndNewUrls = new NotNullLazyValue>() { + @NotNull + @Override + protected Pair compute() { + final String newUrl = propertiesFile.getVirtualFile().getUrl(); + return Pair.create(oldParentUrl + newUrl.substring(newParentUrl.length()), newUrl); + } + }; + + if (!myState.getDissociatedFiles().isEmpty()) { + if (myState.getDissociatedFiles().remove(oldAndNewUrls.getValue().getFirst())) { + myState.getDissociatedFiles().add(oldAndNewUrls.getValue().getSecond()); } } + + if (!myState.getCustomResourceBundles().isEmpty()) { + for (CustomResourceBundleState customResourceBundleState : myState.getCustomResourceBundles()) { + if (customResourceBundleState.getFileUrls().remove(oldAndNewUrls.getValue().getFirst())) { + customResourceBundleState.getFileUrls().add(oldAndNewUrls.getValue().getSecond()); + break; + } + } + } + } @Nullable @@ -151,6 +167,11 @@ public class ResourceBundleManager implements PersistentStateComponent myCheckoutURLs = new ArrayList(); public List myTypedURLs = new ArrayList(); public String mySvnCommandLine = "svn"; + public String myExecutableLocale = SvnConfigurable.EN_US_LOCALE; } private ConfigurationBean myConfigurationBean; @@ -74,6 +76,15 @@ public class SvnApplicationSettings implements PersistentStateComponentEmulates the behavior when Subversion commands are executed directly from the terminal (in the interactive mode).
\ This is required to handle password/passphrase prompts for svn+ssh repositories, and trust invalid server certificates for https repositories. +command.line.locale.label=Locale\: +command.line.locale.system.default.title= ssh.settings.title=SSH Settings ssh.settings.executable.label=SSH executable\: diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.form b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.form index b3d5afb2e2d4..c09b5cee65cd 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.form +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.form @@ -18,7 +18,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -87,7 +87,7 @@ - + @@ -96,7 +96,7 @@ - + @@ -123,18 +123,18 @@ - + - + - + @@ -156,23 +156,47 @@
- + + - + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.java index 2433a816adce..b12a830a722e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.java @@ -24,6 +24,8 @@ import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.ComboBox; +import com.intellij.openapi.ui.FixedComboBoxEditor; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.SystemInfo; @@ -31,10 +33,14 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.ui.CollectionComboBoxModel; +import com.intellij.ui.ListCellRendererWrapper; import com.intellij.ui.MultiLineTooltipUI; import com.intellij.ui.components.JBCheckBox; import com.intellij.ui.components.JBRadioButton; import com.intellij.util.Consumer; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -47,11 +53,18 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; import java.io.File; +import java.util.List; public class SvnConfigurable implements Configurable { public static final String DISPLAY_NAME = SvnVcs.VCS_DISPLAY_NAME; + + public static final String EN_US_LOCALE = "en_US.UTF-8"; + public static final List EXECUTABLE_LOCALES = ContainerUtil.newArrayList("", EN_US_LOCALE, "C.UTF-8", "C"); + private final Project myProject; private JCheckBox myUseDefaultCheckBox; private TextFieldWithBrowseButton myConfigurationDirectoryText; @@ -68,11 +81,13 @@ public class SvnConfigurable implements Configurable { private JCheckBox myShowMergeSourceInAnnotate; private JBCheckBox myWithCommandLineClient; private JBCheckBox myRunUnderTerminal; + private ComboBox myLocalesList; private JSpinner myNumRevsInAnnotations; private JCheckBox myMaximumNumberOfRevisionsCheckBox; private JSpinner mySSHConnectionTimeout; private JSpinner mySSHReadTimeout; private TextFieldWithBrowseButton myCommandLineClient; + private JPanel myCommandLineClientOptions; private JSpinner myHttpTimeout; private JBRadioButton mySSLv3RadioButton; private JBRadioButton myTLSv1RadioButton; @@ -85,12 +100,13 @@ public class SvnConfigurable implements Configurable { public SvnConfigurable(Project project) { myProject = project; - myWithCommandLineClient.addActionListener(new ActionListener() { + myWithCommandLineClient.addItemListener(new ItemListener() { @Override - public void actionPerformed(ActionEvent e) { - myRunUnderTerminal.setEnabled(myWithCommandLineClient.isSelected()); + public void itemStateChanged(ItemEvent e) { + enableCommandLineClientOptions(); } }); + enableCommandLineClientOptions(); myUseDefaultCheckBox.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent e) { boolean enabled = !myUseDefaultCheckBox.isSelected(); @@ -108,7 +124,28 @@ public class SvnConfigurable implements Configurable { } }); myCommandLineClient.addBrowseFolderListener("Subversion", "Select path to Subversion executable (1.7+)", project, - FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor()); + FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor()); + //noinspection unchecked + myLocalesList.setModel(new CollectionComboBoxModel(EXECUTABLE_LOCALES)); + myLocalesList.setEditable(true); + FixedComboBoxEditor editor = new FixedComboBoxEditor(); + editor.getField().getEmptyText().setText(SvnBundle.message("command.line.locale.system.default.title")); + myLocalesList.setEditor(editor); + myLocalesList.setRenderer(new ListCellRendererWrapper() { + + @Override + public void customize(JList list, String value, int index, boolean selected, boolean hasFocus) { + setText(StringUtil.isEmpty(value) ? SvnBundle.message("command.line.locale.system.default.title") : value); + } + }); + myLocalesList.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + myLocalesList.getEditor().setItem(myLocalesList.getSelectedItem()); + } + } + }); myClearAuthButton.addActionListener(new ActionListener(){ public void actionPerformed(final ActionEvent e) { @@ -175,6 +212,10 @@ public class SvnConfigurable implements Configurable { mySshSettingsPanel.load(SvnConfiguration.getInstance(myProject)); } + public void enableCommandLineClientOptions() { + UIUtil.setEnabled(myCommandLineClientOptions, myWithCommandLineClient.isSelected(), true); + } + public static void selectConfigurationDirectory(@NotNull String path, @NotNull final Consumer dirConsumer, final Project project, @@ -263,6 +304,7 @@ public class SvnConfigurable implements Configurable { if (! getSelectedSSL().equals(configuration.getSslProtocols())) return true; final SvnApplicationSettings applicationSettings17 = SvnApplicationSettings.getInstance(); if (! Comparing.equal(applicationSettings17.getCommandLinePath(), myCommandLineClient.getText().trim())) return true; + if (!Comparing.equal(applicationSettings17.getExecutableLocale(), myLocalesList.getEditor().getItem())) return true; if (!configuration.getConfigurationDirectory().equals(myConfigurationDirectoryText.getText().trim())) return true; return mySshSettingsPanel.isModified(configuration); } @@ -292,13 +334,16 @@ public class SvnConfigurable implements Configurable { final SvnApplicationSettings applicationSettings17 = SvnApplicationSettings.getInstance(); boolean reloadWorkingCopies = !acceleration().equals(configuration.getUseAcceleration()) || - !StringUtil.equals(applicationSettings17.getCommandLinePath(), myCommandLineClient.getText().trim()); + !StringUtil.equals(applicationSettings17.getCommandLinePath(), myCommandLineClient.getText().trim()) || + !StringUtil.equals(applicationSettings17.getExecutableLocale(), + myLocalesList.getEditor().getItem().toString()); configuration.setUseAcceleration(acceleration()); configuration.setRunUnderTerminal(myRunUnderTerminal.isSelected()); configuration.setSslProtocols(getSelectedSSL()); SvnVcs.getInstance(myProject).getSvnKitManager().refreshSSLProperty(); applicationSettings17.setCommandLinePath(myCommandLineClient.getText().trim()); + applicationSettings17.setExecutableLocale(myLocalesList.getEditor().getItem().toString()); boolean isClientValid = vcs17.checkCommandLineVersion(); if (isClientValid && reloadWorkingCopies) { vcs17.invokeRefreshSvnRoots(); @@ -342,9 +387,9 @@ public class SvnConfigurable implements Configurable { myHttpTimeout.setValue(Long.valueOf(configuration.getHttpTimeout() / 1000)); myWithCommandLineClient.setSelected(configuration.isCommandLine()); myRunUnderTerminal.setSelected(configuration.isRunUnderTerminal()); - myRunUnderTerminal.setEnabled(myWithCommandLineClient.isSelected()); final SvnApplicationSettings applicationSettings17 = SvnApplicationSettings.getInstance(); myCommandLineClient.setText(applicationSettings17.getCommandLinePath()); + myLocalesList.setSelectedItem(applicationSettings17.getExecutableLocale()); if (SvnConfiguration.SSLProtocols.sslv3.equals(configuration.getSslProtocols())) { mySSLv3RadioButton.setSelected(true); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdVersionClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdVersionClient.java index 5b1484944285..95b4734f84d1 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdVersionClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdVersionClient.java @@ -30,7 +30,8 @@ public class CmdVersionClient extends BaseSvnClient implements VersionClient { Command command = new Command(SvnCommandName.version); command.put("--quiet"); - CommandExecutor executor = new CommandExecutor(SvnApplicationSettings.getInstance().getCommandLinePath(), command); + SvnApplicationSettings settings = SvnApplicationSettings.getInstance(); + CommandExecutor executor = new CommandExecutor(settings.getCommandLinePath(), settings.getExecutableLocale(), command); executor.run(30 * 1000); return executor.getProcessOutput(); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java index cdca82de6966..97c5f9c00ed2 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java @@ -23,7 +23,6 @@ import com.intellij.openapi.application.PathManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Key; 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.util.EventDispatcher; @@ -58,6 +57,7 @@ public class CommandExecutor { private volatile String myDestroyReason; private volatile boolean myWasCancelled; @NotNull protected final GeneralCommandLine myCommandLine; + @NotNull protected final String myLocale; protected Process myProcess; protected SvnProcessHandler myHandler; private OutputStreamWriter myProcessWriter; @@ -72,11 +72,10 @@ public class CommandExecutor { @Nullable private final LineCommandListener myResultBuilder; @NotNull private final Command myCommand; - public CommandExecutor(@NotNull @NonNls String exePath, @NotNull Command command) { + public CommandExecutor(@NotNull @NonNls String exePath, @NotNull String locale, @NotNull Command command) { myCommand = command; myResultBuilder = command.getResultBuilder(); - if (myResultBuilder != null) - { + if (myResultBuilder != null) { myListeners.addListener(myResultBuilder); // cancel tracker should be executed after result builder myListeners.addListener(new CommandCancelTracker()); @@ -90,6 +89,7 @@ public class CommandExecutor { } myCommandLine.addParameter(command.getName().getName()); myCommandLine.addParameters(prepareParameters(command)); + myLocale = locale; myExitCodeReference = new AtomicReference(); } @@ -159,13 +159,12 @@ public class CommandExecutor { } private void setupLocale() { - String locale = Registry.stringValue("svn.executable.locale"); - Map environment = myCommandLine.getEnvironment(); + if (!StringUtil.isEmpty(myLocale)) { + Map environment = myCommandLine.getEnvironment(); - // TODO: check if we need to set LC_ALL to configured locale or just clear it - environment.put("LC_ALL", ""); - environment.put("LC_MESSAGES", locale); - environment.put("LANG", locale); + environment.put("LANGUAGE", ""); + environment.put("LC_ALL", myLocale); + } } private void ensureMessageFile() throws SvnBindException { @@ -413,7 +412,7 @@ public class CommandExecutor { * @throws IllegalStateException if process has not been started */ protected void checkStarted() { - if (! isStarted()) { + if (!isStarted()) { throw new IllegalStateException("The process is not started yet"); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java index 46b716c3bde2..a64821e24aad 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java @@ -43,11 +43,15 @@ public class CommandRuntime { @NotNull private final SvnVcs myVcs; @NotNull private final List myModules; private final String exePath; + @NotNull private final String executableLocale; public CommandRuntime(@NotNull SvnVcs vcs, @NotNull AuthenticationService authenticationService) { myVcs = vcs; myAuthenticationService = authenticationService; - exePath = SvnApplicationSettings.getInstance().getCommandLinePath(); + + SvnApplicationSettings settings = SvnApplicationSettings.getInstance(); + exePath = settings.getCommandLinePath(); + executableLocale = settings.getExecutableLocale(); myModules = ContainerUtil.newArrayList(); myModules.add(new CommandParametersResolutionModule(this)); @@ -218,7 +222,7 @@ public class CommandRuntime { if (!myVcs.getSvnConfiguration().isRunUnderTerminal() || isLocal(command)) { command.putIfNotPresent("--non-interactive"); - executor = new CommandExecutor(exePath, command); + executor = new CommandExecutor(exePath, executableLocale, command); } else { // do not explicitly specify "--force-interactive" as it is not supported in svn 1.7 - commands will be interactive by default as @@ -234,7 +238,9 @@ public class CommandRuntime { @NotNull private TerminalExecutor newTerminalExecutor(@NotNull Command command) { - return SystemInfo.isWindows ? new WinTerminalExecutor(exePath, command) : new TerminalExecutor(exePath, command); + return SystemInfo.isWindows + ? new WinTerminalExecutor(exePath, executableLocale, command) + : new TerminalExecutor(exePath, executableLocale, command); } public static boolean isLocal(@NotNull Command command) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalExecutor.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalExecutor.java index 63fa3bbc0700..1509629b032b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalExecutor.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalExecutor.java @@ -35,8 +35,8 @@ public class TerminalExecutor extends CommandExecutor { private final List myInteractiveListeners = ContainerUtil.createLockFreeCopyOnWriteList(); - public TerminalExecutor(@NotNull @NonNls String exePath, @NotNull Command command) { - super(exePath, command); + public TerminalExecutor(@NotNull @NonNls String exePath, @NotNull String locale, @NotNull Command command) { + super(exePath, locale, command); } public void addInteractiveListener(@NotNull InteractiveCommandListener listener) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/WinTerminalExecutor.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/WinTerminalExecutor.java index e08594d33c28..08979ab6d3e3 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/WinTerminalExecutor.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/WinTerminalExecutor.java @@ -49,8 +49,8 @@ public class WinTerminalExecutor extends TerminalExecutor { @Nullable private File myRedirectFile; @Nullable private FileInputStream myRedirectStream; - public WinTerminalExecutor(@NotNull @NonNls String exePath, @NotNull Command command) { - super(exePath, command); + public WinTerminalExecutor(@NotNull @NonNls String exePath, @NotNull String locale, @NotNull Command command) { + super(exePath, locale, command); } @NotNull diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomServiceImpl.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomServiceImpl.java index 94987bc604a9..eb8c57a9c281 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomServiceImpl.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomServiceImpl.java @@ -164,12 +164,19 @@ public class DomServiceImpl extends DomService { @Override public Collection getDomFileCandidates(Class description, Project project) { - return FileBasedIndex.getInstance().getContainingFiles(DomFileIndex.NAME, description.getName(), GlobalSearchScope.allScope(project)); + return getDomFileCandidates(description, project, GlobalSearchScope.allScope(project)); + } + + @Override + public Collection getDomFileCandidates(Class rootElementClass, + Project project, + final GlobalSearchScope scope) { + return FileBasedIndex.getInstance().getContainingFiles(DomFileIndex.NAME, rootElementClass.getName(), scope); } @Override public List> getFileElements(final Class clazz, final Project project, @Nullable final GlobalSearchScope scope) { - final Collection list = scope == null ? getDomFileCandidates(clazz, project) : getDomFileCandidates(clazz, project, scope); + final Collection list = getDomFileCandidates(clazz, project, scope != null ? scope : GlobalSearchScope.allScope(project)); final ArrayList> result = new ArrayList>(list.size()); for (VirtualFile file : list) { final PsiFile psiFile = PsiManager.getInstance(project).findFile(file); @@ -189,5 +196,4 @@ public class DomServiceImpl extends DomService { public StructureViewBuilder createSimpleStructureViewBuilder(final XmlFile file, final Function modeProvider) { return new DomStructureViewBuilder(file, modeProvider); } - } diff --git a/xml/dom-openapi/src/com/intellij/util/xml/DomFileDescription.java b/xml/dom-openapi/src/com/intellij/util/xml/DomFileDescription.java index eb5de3eebf43..97950b30037e 100644 --- a/xml/dom-openapi/src/com/intellij/util/xml/DomFileDescription.java +++ b/xml/dom-openapi/src/com/intellij/util/xml/DomFileDescription.java @@ -126,7 +126,8 @@ public class DomFileDescription { /** * @return some version. Override and change (e.g. super.getVersion()+1) when after some changes some files stopped being * described by this description or vice versa, so that the - * {@link com.intellij.util.xml.DomService#getDomFileCandidates(Class, com.intellij.openapi.project.Project)} index is rebuilt correctly. + * {@link com.intellij.util.xml.DomService#getDomFileCandidates(Class, com.intellij.openapi.project.Project, com.intellij.psi.search.GlobalSearchScope)} + * index is rebuilt correctly. */ public int getVersion() { return myRootTagName.hashCode(); diff --git a/xml/dom-openapi/src/com/intellij/util/xml/DomService.java b/xml/dom-openapi/src/com/intellij/util/xml/DomService.java index dced490f43d5..a2d567e9c87a 100644 --- a/xml/dom-openapi/src/com/intellij/util/xml/DomService.java +++ b/xml/dom-openapi/src/com/intellij/util/xml/DomService.java @@ -19,12 +19,10 @@ package com.intellij.util.xml; import com.intellij.ide.structureView.StructureViewBuilder; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Condition; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.xml.XmlFile; import com.intellij.util.Function; -import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -44,24 +42,21 @@ public abstract class DomService { return ourCachedInstance; } + /** + * @deprecated use {@link #getDomFileCandidates(Class, com.intellij.openapi.project.Project, com.intellij.psi.search.GlobalSearchScope)} (to remove in IDEA 15) + */ + public abstract Collection getDomFileCandidates(Class description, Project project); + /** * @param rootElementClass class of root (file-level) element in DOM model - * @param project current project - * @param scope search scope + * @param project current project + * @param scope search scope * @return files containing given root element - * * @see #getFileElements(Class, com.intellij.openapi.project.Project, com.intellij.psi.search.GlobalSearchScope) */ - public Collection getDomFileCandidates(Class rootElementClass, Project project, final GlobalSearchScope scope) { - return ContainerUtil.findAll(getDomFileCandidates(rootElementClass, project), new Condition() { - @Override - public boolean value(final VirtualFile file) { - return scope.contains(file); - } - }); - } - - public abstract Collection getDomFileCandidates(Class description, Project project); + public abstract Collection getDomFileCandidates(Class rootElementClass, + Project project, + GlobalSearchScope scope); /** * @param rootElementClass class of root (file-level) element in DOM model @@ -89,5 +84,7 @@ public abstract class DomService { public enum StructureViewMode { SHOW, SHOW_CHILDREN, SKIP } - public abstract StructureViewBuilder createSimpleStructureViewBuilder(final XmlFile file, final Function modeProvider); + + public abstract StructureViewBuilder createSimpleStructureViewBuilder(final XmlFile file, + final Function modeProvider); } diff --git a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlElementDescriptorImpl.java b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlElementDescriptorImpl.java index 7bf9f02710b3..49d3c4c12245 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlElementDescriptorImpl.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlElementDescriptorImpl.java @@ -219,7 +219,6 @@ public class XmlElementDescriptorImpl extends XsdEnumerationDescriptor if (type instanceof ComplexTypeDescriptor) { final ComplexTypeDescriptor descriptor = (ComplexTypeDescriptor)type; - String contextNs; PsiFile containingFile = context != null ? context.getContainingFile():null; if (context != null && !containingFile.isPhysical()) { @@ -227,10 +226,11 @@ public class XmlElementDescriptorImpl extends XsdEnumerationDescriptor //context = context.getParentTag(); } + String contextNs; if (context != null && - ( descriptor.canContainTag(context.getLocalName(), contextNs = context.getNamespace(), context ) && - (!contextNs.equals(getNamespace()) || descriptor.hasAnyInContentModel()) - ) ) { + descriptor.canContainTag(context.getLocalName(), contextNs = context.getNamespace(), context) && + (!contextNs.equals(getNamespace()) || descriptor.hasAnyInContentModel()) && + containingFile instanceof XmlFile) { // JSXmlLiteralExpressionImpl is crazy final XmlNSDescriptor nsDescriptor = getNSDescriptor(); if (nsDescriptor != null) {