diff --git a/build/lib/gant/jps-sources.zip b/build/lib/gant/jps-sources.zip index 2ec496139390..ec76cf49df46 100644 Binary files a/build/lib/gant/jps-sources.zip and b/build/lib/gant/jps-sources.zip differ diff --git a/build/lib/gant/lib/jps.jar b/build/lib/gant/lib/jps.jar index c59de9e1de98..495f788f98b7 100644 Binary files a/build/lib/gant/lib/jps.jar and b/build/lib/gant/lib/jps.jar differ diff --git a/build/scripts/common_tests.gant b/build/scripts/common_tests.gant index 077abbab7318..f22fd6fd58c8 100644 --- a/build/scripts/common_tests.gant +++ b/build/scripts/common_tests.gant @@ -6,7 +6,7 @@ requireProperty("out", "$home/out/classes") target(compile: "Compile project") { loadProject() - project["javac"] = "$jdkHome/bin/javac" + project.builder.useInProcessJavac = true project.targetFolder = out ant.delete(dir: "$home/reports") project.clean() diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java b/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java index f883024fdc71..5c8a5679c08c 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java @@ -85,6 +85,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { private static final FileAttribute ourSourceFileAttribute = new FileAttribute("_make_source_file_info_", 3); private static final FileAttribute ourOutputFileAttribute = new FileAttribute("_make_output_file_info_", 3); + private final Object myDataLock = new Object(); private final TIntObjectHashMap mySourcesToRecompile = new TIntObjectHashMap(); // ProjectId->set of source file paths private PersistentHashMap>> myOutputRootsStorage; // ProjectId->map[moduleId->Pair(outputDirId, testOutputDirId)] private final TIntObjectHashMap> myOutputsToDelete = new TIntObjectHashMap>(); // Map: projectId -> Map{output path -> [sourceUrl; classname]} @@ -158,7 +159,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { final CompilerConfiguration configuration = CompilerConfiguration.getInstance(project); final boolean _forceCompile = forceCompile || isRebuild; final Set selectedForRecompilation = new HashSet(); - synchronized (mySourcesToRecompile) { + synchronized (myDataLock) { final TIntHashSet pathsToRecompile = mySourcesToRecompile.get(projectId); if (_forceCompile || pathsToRecompile != null && !pathsToRecompile.isEmpty()) { if (ourDebugMode) { @@ -214,10 +215,8 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { } } } - } - // it is important that files to delete are collected after the files to compile (see what happens if forceCompile == true) - if (!isRebuild) { - synchronized (myOutputsToDelete) { + // it is important that files to delete are collected after the files to compile (see what happens if forceCompile == true) + if (!isRebuild) { final Map outputsToDelete = myOutputsToDelete.get(projectId); if (outputsToDelete != null) { final VirtualFileManager vfm = VirtualFileManager.getInstance(); @@ -233,6 +232,16 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { continue; // do not collect files that were compiled by another compiler } if (!selectedForRecompilation.contains(srcFile)) { + if (!isMarkedForRecompilation(projectId, getFileId(srcFile))) { + if (LOG.isDebugEnabled() || ourDebugMode) { + final String message = "Found zombie entry (output is marked, but source is present and up-to-date): " + outputPath; + LOG.debug(message); + if (ourDebugMode) { + System.out.println(message); + } + } + zombieEntries.add(outputPath); + } continue; } } @@ -397,7 +406,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { final DataInputStream is = new DataInputStream(new BufferedInputStream(new FileInputStream(file))); try { final int projectsCount = is.readInt(); - synchronized (myOutputsToDelete) { + synchronized (myDataLock) { for (int idx = 0; idx < projectsCount; idx++) { final int projectId = is.readInt(); final int size = is.readInt(); @@ -429,7 +438,9 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { } catch (IOException e) { LOG.info(e); - myOutputsToDelete.clear(); + synchronized (myDataLock) { + myOutputsToDelete.clear(); + } FileUtil.delete(file); } @@ -503,7 +514,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { FileUtil.createParentDirs(file); final DataOutputStream os = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))); try { - synchronized (myOutputsToDelete) { + synchronized (myDataLock) { final int[] keys = myOutputsToDelete.keys(); os.writeInt(keys.length); for (int projectId : keys) { @@ -1152,7 +1163,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { } } myConnections.remove(project).disconnect(); - synchronized (mySourcesToRecompile) { + synchronized (myDataLock) { mySourcesToRecompile.remove(projectId); } } @@ -1317,7 +1328,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { final SourceFileInfo srcInfo = preloadedInfo != null? preloadedInfo : loadSourceInfo(srcFile); final boolean alreadyMarked; - synchronized (mySourcesToRecompile) { + synchronized (myDataLock) { TIntHashSet set = mySourcesToRecompile.get(projectId); if (set == null) { set = new TIntHashSet(); @@ -1341,7 +1352,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { } private void removeSourceForRecompilation(final int projectId, final int srcId) { - synchronized (mySourcesToRecompile) { + synchronized (myDataLock) { TIntHashSet set = mySourcesToRecompile.get(projectId); if (set != null) { set.remove(srcId); @@ -1357,7 +1368,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { } private boolean isMarkedForRecompilation(int projectId, final int srcId) { - synchronized (mySourcesToRecompile) { + synchronized (myDataLock) { final TIntHashSet set = mySourcesToRecompile.get(projectId); return set != null && set.contains(srcId); } diff --git a/java/java-impl/src/com/intellij/codeInsight/preview/JavaPreviewHintProvider.java b/java/java-impl/src/com/intellij/codeInsight/preview/JavaPreviewHintProvider.java index bc3d1937a319..a9cdcf97f160 100644 --- a/java/java-impl/src/com/intellij/codeInsight/preview/JavaPreviewHintProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/preview/JavaPreviewHintProvider.java @@ -15,10 +15,10 @@ */ package com.intellij.codeInsight.preview; +import com.intellij.patterns.PlatformPatterns; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayUtil; -import com.intellij.patterns.PlatformPatterns; import com.intellij.xml.util.ColorSampleLookupValue; import org.jetbrains.annotations.NotNull; @@ -60,7 +60,10 @@ public class JavaPreviewHintProvider implements PreviewHintProvider { final Object o = helper.computeConstantExpression(each); if (o instanceof Integer) { values[i] = ((Integer)o).intValue(); - values[i] = values[i] > 255 ? 255 : values[i] < 0 ? 0 : values[i]; + if (expressions.length != 1) { + values[i] = values[i] > 255 ? 255 : values[i] < 0 ? 0 : values[i]; + } + i++; } else if (o instanceof Float) { @@ -73,18 +76,22 @@ public class JavaPreviewHintProvider implements PreviewHintProvider { Color c = null; if (i == expressions.length) { - switch (values.length) { - case 1: - c = new Color(values[0]); - break; - case 3: - c = new Color(values[0], values[1], values[2]); - break; - case 4: - c = new Color(values[0], values[1], values[2], values[3]); - break; - default: - break; + if (i == 1 && values[0] > 255) { + c = new Color(values[0]); + } else { + switch (values.length) { + case 1: + c = new Color(values[0]); + break; + case 3: + c = new Color(values[0], values[1], values[2]); + break; + case 4: + c = new Color(values[0], values[1], values[2], values[3]); + break; + default: + break; + } } } else if (j == expressions.length) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/closure/EachToForIntention.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/closure/EachToForIntention.java index 17333c0a9fdb..9656453f486c 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/closure/EachToForIntention.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/closure/EachToForIntention.java @@ -69,12 +69,13 @@ public class EachToForIntention extends Intention { StringBuilder builder = new StringBuilder(); builder.append("for (").append(var).append(" in ").append(qualifier.getText()).append(") {\n"); String text = block.getText(); - int index = text.indexOf("->"); - if (index == -1) { - index = 1; + final PsiElement blockArrow = block.getArrow(); + int index; + if (blockArrow != null) { + index = blockArrow.getStartOffsetInParent() + blockArrow.getTextLength(); } else { - index += 2; + index = 1; } while (index < text.length() && Character.isWhitespace(text.charAt(index))) index++; text = text.substring(index, text.length() - 1); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/blocks/GrClosableBlock.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/blocks/GrClosableBlock.java index 1a11d3775c5f..66ad117e2e61 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/blocks/GrClosableBlock.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/blocks/GrClosableBlock.java @@ -16,6 +16,7 @@ package org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiParameter; import com.intellij.psi.PsiType; import org.jetbrains.annotations.Nullable; @@ -44,4 +45,7 @@ public interface GrClosableBlock extends GrExpression, GrCodeBlock, GrParameters PsiType getReturnType(); PsiParameter[] getAllParameters(); + + @Nullable + PsiElement getArrow(); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java index 3ca2ff237f3b..0aa8f7ae378e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java @@ -24,7 +24,6 @@ import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; -import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; @@ -114,13 +113,19 @@ public class GrClosableBlockImpl extends GrBlockImpl implements GrClosableBlock return new PsiParameter[]{getSyntheticItParameter()}; } + @Override + @Nullable + public PsiElement getArrow() { + return findChildByType(GroovyTokenTypes.mCLOSABLE_BLOCK_OP); + } + public GrParameterListImpl getParameterList() { return findChildByClass(GrParameterListImpl.class); } public void addParameter(GrParameter parameter) { GrParameterList parameterList = getParameterList(); - if (findChildByType(GroovyTokenTypes.mCLOSABLE_BLOCK_OP) == null) { + if (getArrow() == null) { ASTNode next = parameterList.getNode().getTreeNext(); getNode().addLeaf(GroovyTokenTypes.mCLOSABLE_BLOCK_OP, "->", next); getNode().addLeaf(GroovyTokenTypes.mNLS, "\n", next); @@ -130,7 +135,7 @@ public class GrClosableBlockImpl extends GrBlockImpl implements GrClosableBlock } public boolean hasParametersSection() { - return findChildByType(GroovyElementTypes.mCLOSABLE_BLOCK_OP) != null; + return getArrow() != null; } public PsiType getType() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/GrIntentionTestCase.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/GrIntentionTestCase.java index 79838774e574..2c12cbc405dc 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/GrIntentionTestCase.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/GrIntentionTestCase.java @@ -26,7 +26,7 @@ import java.util.List; * @author Maxim.Medvedev */ public abstract class GrIntentionTestCase extends LightCodeInsightFixtureTestCase { - protected void doTest(String hint, boolean intentionExists) throws Exception { + protected void doTest(String hint, boolean intentionExists) { myFixture.configureByFile(getTestName(false) + ".groovy"); final List list = myFixture.filterAvailableIntentions(hint); if (intentionExists) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/closure/eachToFor/EachToForIntentionTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/closure/eachToFor/EachToForIntentionTest.java index 7bfb56d79b0c..30e4ae8beb36 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/closure/eachToFor/EachToForIntentionTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/closure/eachToFor/EachToForIntentionTest.java @@ -28,19 +28,23 @@ public class EachToForIntentionTest extends GrIntentionTestCase { return TestUtils.getTestDataPath() + "intentions/EachToFor/"; } - public void testEachToFor() throws Throwable { + public void testEachToFor() { doTest("Replace with For-In", true); } - public void testEachToForWithFinal() throws Throwable { + public void testEachToForWithFinal() { doTest("Replace with For-In", true); } - public void testEachToForWithDefaultVariable() throws Throwable { + public void testEachToForWithDefaultVariable() { doTest("Replace with For-In", true); } - public void testEachForInWithNoQualifier () throws Throwable { + public void testEachForInWithNoQualifier() { + doTest("Replace with For-In", true); + } + + public void testWithClosureInBody() { doTest("Replace with For-In", true); } } diff --git a/plugins/groovy/testdata/intentions/EachToFor/WithClosureInBody.groovy b/plugins/groovy/testdata/intentions/EachToFor/WithClosureInBody.groovy new file mode 100644 index 000000000000..b5b7bb6c3aa5 --- /dev/null +++ b/plugins/groovy/testdata/intentions/EachToFor/WithClosureInBody.groovy @@ -0,0 +1,10 @@ +[].each { + if (it == 2) { + println 2 + } + if (it == 3) { + println { String s -> + println s + } + } +} \ No newline at end of file diff --git a/plugins/groovy/testdata/intentions/EachToFor/WithClosureInBody_after.groovy b/plugins/groovy/testdata/intentions/EachToFor/WithClosureInBody_after.groovy new file mode 100644 index 000000000000..d63dbe71b6ce --- /dev/null +++ b/plugins/groovy/testdata/intentions/EachToFor/WithClosureInBody_after.groovy @@ -0,0 +1,10 @@ +for (it in []) { + if (it == 2) { + println 2 + } + if (it == 3) { + println { String s -> + println s + } + } +} \ No newline at end of file diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/ZenCodingTemplate.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/ZenCodingTemplate.java index 46b6c916ec76..1c42fad48c59 100644 --- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/ZenCodingTemplate.java +++ b/xml/impl/src/com/intellij/codeInsight/template/zencoding/ZenCodingTemplate.java @@ -94,7 +94,7 @@ public abstract class ZenCodingTemplate implements CustomLiveTemplate { } else if (c == '\'') inApostrophes = false; } - else if (i == n - 1 || (i < n - 2 && DELIMS.indexOf(c) >= 0) || c == ')') { + else if (i == n - 1 || (c == ')' || c == '*' || i < n - 2 && DELIMS.indexOf(c) >= 0)) { String key = templateKeyBuilder.toString(); templateKeyBuilder = new StringBuilder(); int num = parseNonNegativeInt(key); @@ -266,12 +266,12 @@ public abstract class ZenCodingTemplate implements CustomLiveTemplate { ZenCodingGenerator generator = findApplicableGenerator(node, context); List filters = getFilters(node, context); - List genNodes = node.expand(-1); + List genNodes = node.expand(-1, surroundedText); LiveTemplateBuilder builder = new LiveTemplateBuilder(); int end = -1; for (int i = 0, genNodesSize = genNodes.size(); i < genNodesSize; i++) { GenerationNode genNode = genNodes.get(i); - TemplateImpl template = genNode.generate(callback, surroundedText, generator, filters); + TemplateImpl template = genNode.generate(callback, generator, filters); int e = builder.insertTemplate(builder.length(), template, null); if (end == -1 && end < builder.length()) { end = e; @@ -387,7 +387,7 @@ public abstract class ZenCodingTemplate implements CustomLiveTemplate { @Nullable private ZenCodingNode parseAddOrMore() { - ZenCodingNode mul = parseMul(true); + ZenCodingNode mul = parseMul(); if (mul == null) { return null; } @@ -416,17 +416,17 @@ public abstract class ZenCodingTemplate implements CustomLiveTemplate { } @Nullable - private ZenCodingNode parseMul(boolean canBeSingle) { + private ZenCodingNode parseMul() { ZenCodingNode exp = parseExpressionInBraces(); if (exp == null) { return null; } ZenCodingToken operationToken = nextToken(); if (!(operationToken instanceof OperationToken)) { - return canBeSingle ? exp : null; + return exp; } if (((OperationToken)operationToken).getSign() != '*') { - return canBeSingle ? exp : null; + return exp; } myIndex++; ZenCodingToken numberToken = nextToken(); @@ -434,7 +434,7 @@ public abstract class ZenCodingTemplate implements CustomLiveTemplate { myIndex++; return new MulOperationNode(exp, ((NumberToken)numberToken).getNumber()); } - return null; + return new UnaryMulOperationNode(exp); } @Nullable diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/AddOperationNode.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/AddOperationNode.java index c61a22dc160d..1376eb9219fb 100644 --- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/AddOperationNode.java +++ b/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/AddOperationNode.java @@ -42,14 +42,11 @@ public class AddOperationNode extends ZenCodingNode { @NotNull @Override - public List expand(int numberInIteration) { + public List expand(int numberInIteration, String surroundedText) { List result = new ArrayList(); - List leftNodes = myLeftOperand.expand(numberInIteration); - for (GenerationNode leftNode : leftNodes) { - leftNode.setToInsertChildren(false); - } + List leftNodes = myLeftOperand.expand(numberInIteration, null); result.addAll(leftNodes); - result.addAll(myRightOperand.expand(numberInIteration)); + result.addAll(myRightOperand.expand(numberInIteration, surroundedText)); return result; } } diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/FilterNode.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/FilterNode.java index d19b025d9621..6d6f2777ae96 100644 --- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/FilterNode.java +++ b/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/FilterNode.java @@ -41,7 +41,7 @@ public class FilterNode extends ZenCodingNode { @NotNull @Override - public List expand(int numberInIteration) { - return myNode.expand(numberInIteration); + public List expand(int numberInIteration, String surroundedText) { + return myNode.expand(numberInIteration, surroundedText); } } diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/GenerationNode.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/GenerationNode.java index 0cca2ddec03e..88dcb7b1622a 100644 --- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/GenerationNode.java +++ b/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/GenerationNode.java @@ -56,16 +56,13 @@ public class GenerationNode { private final TemplateToken myTemplateToken; private final List myChildren; private final int myNumberInIteration; - private boolean myToInsertChildren = true; + private final String mySurroundedText; - public GenerationNode(TemplateToken templateToken, List children, int numberInIteration) { + public GenerationNode(TemplateToken templateToken, List children, int numberInIteration, String surroundedText) { myTemplateToken = templateToken; myChildren = children; myNumberInIteration = numberInIteration; - } - - public void setToInsertChildren(boolean toInsertChildren) { - myToInsertChildren = toInsertChildren; + mySurroundedText = surroundedText; } public List getChildren() { @@ -73,11 +70,6 @@ public class GenerationNode { } public void addChildren(Collection child) { - for (GenerationNode node : child) { - if (!myToInsertChildren) { - node.myToInsertChildren = false; - } - } myChildren.addAll(child); } @@ -85,10 +77,6 @@ public class GenerationNode { return myChildren.size() == 0; } - public boolean isToInsertChildren() { - return myToInsertChildren; - } - private boolean isBlockTag() { if (myTemplateToken instanceof XmlTemplateToken) { XmlFile xmlFile = ((XmlTemplateToken)myTemplateToken).getFile(); @@ -105,7 +93,6 @@ public class GenerationNode { @NotNull public TemplateImpl generate(@NotNull CustomTemplateCallback callback, - @Nullable String surroundedText, @Nullable ZenCodingGenerator generator, @NotNull Collection filters) { GenerationNode generationNode = this; @@ -114,14 +101,14 @@ public class GenerationNode { } if (generationNode != this) { - return generationNode.generate(callback, surroundedText, generator, Collections.emptyList()); + return generationNode.generate(callback, generator, Collections.emptyList()); } LiveTemplateBuilder builder = new LiveTemplateBuilder(); int end = -1; boolean hasChildren = myChildren.size() > 0; - String txt = !hasChildren && myToInsertChildren ? surroundedText : null; + String txt = hasChildren ? null : mySurroundedText; TemplateImpl parentTemplate; Map predefinedValues; @@ -176,7 +163,7 @@ public class GenerationNode { for (int i = 0, myChildrenSize = myChildren.size(); i < myChildrenSize; i++) { GenerationNode child = myChildren.get(i); - TemplateImpl childTemplate = child.generate(callback, surroundedText, generator, filters); + TemplateImpl childTemplate = child.generate(callback, generator, filters); boolean blockTag = child.isBlockTag(); diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/MoreOperationNode.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/MoreOperationNode.java index 5985b5f41769..36f6156347c5 100644 --- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/MoreOperationNode.java +++ b/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/MoreOperationNode.java @@ -15,6 +15,7 @@ */ package com.intellij.codeInsight.template.zencoding.nodes; +import com.intellij.openapi.util.text.LineTokenizer; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -42,9 +43,6 @@ public class MoreOperationNode extends ZenCodingNode { } private static void addChildrenToAllLeafs(GenerationNode root, Collection children) { - if (!root.isToInsertChildren()) { - return; - } if (root.isLeaf()) { root.addChildren(children); } @@ -57,25 +55,37 @@ public class MoreOperationNode extends ZenCodingNode { @NotNull @Override - public List expand(int numberInIteration) { - if (myLeftOperand instanceof MulOperationNode) { - MulOperationNode mul = (MulOperationNode)myLeftOperand; - ZenCodingNode node = mul.getLeftOperand(); - int count = mul.getRightOperand(); + public List expand(int numberInIteration, String surroundedText) { + if (myLeftOperand instanceof MulOperationNode || (myLeftOperand instanceof UnaryMulOperationNode && surroundedText != null)) { List result = new ArrayList(); - for (int i = 0; i < count; i++) { - List parentNodes = node.expand(i); - List innerNodes = myRightOperand.expand(i); - for (GenerationNode parentNode : parentNodes) { - addChildrenToAllLeafs(parentNode, innerNodes); + if (myLeftOperand instanceof MulOperationNode) { + MulOperationNode mul = (MulOperationNode)myLeftOperand; + for (int i = 0; i < mul.getRightOperand(); i++) { + List parentNodes = mul.getLeftOperand().expand(i, surroundedText); + List innerNodes = myRightOperand.expand(i, surroundedText); + for (GenerationNode parentNode : parentNodes) { + addChildrenToAllLeafs(parentNode, innerNodes); + } + result.addAll(parentNodes); + } + } + else { + UnaryMulOperationNode unaryMul = (UnaryMulOperationNode)myLeftOperand; + String[] lines = LineTokenizer.tokenize(surroundedText, false); + for (int i = 0; i < lines.length; i++) { + List parentNodes = unaryMul.getOperand().expand(i, lines[i]); + List innerNodes = myRightOperand.expand(i, lines[i]); + for (GenerationNode parentNode : parentNodes) { + addChildrenToAllLeafs(parentNode, innerNodes); + } + result.addAll(parentNodes); } - result.addAll(parentNodes); } return result; } - List leftGenNodes = myLeftOperand.expand(numberInIteration); + List leftGenNodes = myLeftOperand.expand(numberInIteration, surroundedText); for (GenerationNode leftGenNode : leftGenNodes) { - List rightGenNodes = myRightOperand.expand(numberInIteration); + List rightGenNodes = myRightOperand.expand(numberInIteration, surroundedText); addChildrenToAllLeafs(leftGenNode, rightGenNodes); } return leftGenNodes; diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/MulOperationNode.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/MulOperationNode.java index cba28a9f0763..9a122a0e1a45 100644 --- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/MulOperationNode.java +++ b/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/MulOperationNode.java @@ -42,10 +42,10 @@ public class MulOperationNode extends ZenCodingNode { @NotNull @Override - public List expand(int numberInIteration) { + public List expand(int numberInIteration, String surroundedText) { List result = new ArrayList(); for (int i = 0; i < myRightOperand; i++) { - result.addAll(myLeftOperand.expand(i)); + result.addAll(myLeftOperand.expand(i, surroundedText)); } return result; } diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/TemplateNode.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/TemplateNode.java index 9ac59fe1d646..b544e97af1c2 100644 --- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/TemplateNode.java +++ b/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/TemplateNode.java @@ -38,7 +38,8 @@ public class TemplateNode extends ZenCodingNode { @NotNull @Override - public List expand(int numberInIteration) { - return Arrays.asList(new GenerationNode(myTemplateToken, new ArrayList(), numberInIteration)); + public List expand(int numberInIteration, String surroundedText) { + GenerationNode node = new GenerationNode(myTemplateToken, new ArrayList(), numberInIteration, surroundedText); + return Arrays.asList(node); } } diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/UnaryMulOperationNode.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/UnaryMulOperationNode.java new file mode 100644 index 000000000000..8a323badfc7d --- /dev/null +++ b/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/UnaryMulOperationNode.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.template.zencoding.nodes; + +import com.intellij.openapi.util.text.LineTokenizer; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Eugene.Kudelevsky + */ +public class UnaryMulOperationNode extends ZenCodingNode { + private final ZenCodingNode myOperand; + + public UnaryMulOperationNode(ZenCodingNode operand) { + myOperand = operand; + } + + public ZenCodingNode getOperand() { + return myOperand; + } + + @NotNull + @Override + public List expand(int numberInIteration, String surroundedText) { + if (surroundedText == null) { + return myOperand.expand(numberInIteration, surroundedText); + } + String[] lines = LineTokenizer.tokenize(surroundedText, false); + List result = new ArrayList(); + for (int i = 0; i < lines.length; i++) { + result.addAll(myOperand.expand(i, lines[i])); + } + return result; + } +} diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/ZenCodingNode.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/ZenCodingNode.java index 1f6786effb1d..70cbf6afba95 100644 --- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/ZenCodingNode.java +++ b/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/ZenCodingNode.java @@ -24,5 +24,5 @@ import java.util.List; */ public abstract class ZenCodingNode { @NotNull - public abstract List expand(int numberInIteration); + public abstract List expand(int numberInIteration, String surroundedText); } diff --git a/xml/impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/SchemaReferencesProvider.java b/xml/impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/SchemaReferencesProvider.java index 9d7d3856de5a..7bd1dd97968f 100644 --- a/xml/impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/SchemaReferencesProvider.java +++ b/xml/impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/SchemaReferencesProvider.java @@ -679,7 +679,7 @@ public class SchemaReferencesProvider extends PsiReferenceProvider { final XmlAttributeValue attributeValue = (XmlAttributeValue)element; final String prefix = XmlUtil.findPrefixByQualifiedName(attributeValue.getValue()); if (prefix.length() > 0) { - return new SchemaPrefixReference(attributeValue, TextRange.from(1, prefix.length()), prefix); + return new SchemaPrefixReference(attributeValue, TextRange.from(1, prefix.length()), prefix, null); } } return null; diff --git a/xml/impl/src/com/intellij/psi/impl/source/xml/SchemaPrefixReference.java b/xml/impl/src/com/intellij/psi/impl/source/xml/SchemaPrefixReference.java index 84d465a01233..9e21a3be9232 100644 --- a/xml/impl/src/com/intellij/psi/impl/source/xml/SchemaPrefixReference.java +++ b/xml/impl/src/com/intellij/psi/impl/source/xml/SchemaPrefixReference.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl.source.xml; +import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.openapi.util.NullableLazyValue; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; @@ -52,10 +53,13 @@ public class SchemaPrefixReference extends PsiReferenceBase { }; private final String myName; + @Nullable + private final TagNameReference myTagNameReference; - public SchemaPrefixReference(XmlElement element, TextRange range, String name) { + public SchemaPrefixReference(XmlElement element, TextRange range, String name, @Nullable TagNameReference tagNameReference) { super(element, range, true); myName = name; + myTagNameReference = tagNameReference; } public String getNamespacePrefix() { @@ -68,6 +72,9 @@ public class SchemaPrefixReference extends PsiReferenceBase { @NotNull public Object[] getVariants() { + if (myTagNameReference != null) { + return new LookupElement[]{ myTagNameReference.createClosingTagLookupElement(myTagNameReference.getTagElement(), true)}; + } return ArrayUtil.EMPTY_OBJECT_ARRAY; } diff --git a/xml/impl/src/com/intellij/psi/impl/source/xml/TagNameReference.java b/xml/impl/src/com/intellij/psi/impl/source/xml/TagNameReference.java index 8a4da63851ad..a03baa2064bf 100644 --- a/xml/impl/src/com/intellij/psi/impl/source/xml/TagNameReference.java +++ b/xml/impl/src/com/intellij/psi/impl/source/xml/TagNameReference.java @@ -20,6 +20,7 @@ import com.intellij.codeInsight.completion.XmlTagInsertHandler; import com.intellij.codeInsight.lookup.*; import com.intellij.lang.ASTNode; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiReference; @@ -41,6 +42,7 @@ import com.intellij.xml.XmlElementDescriptorAwareAboutChildren; import com.intellij.xml.XmlExtension; import com.intellij.xml.XmlNSDescriptor; import com.intellij.xml.impl.schema.AnyXmlElementDescriptor; +import com.intellij.xml.impl.schema.XmlElementDescriptorImpl; import com.intellij.xml.util.HtmlUtil; import com.intellij.xml.util.XmlUtil; import org.jetbrains.annotations.NotNull; @@ -76,12 +78,14 @@ public class TagNameReference implements PsiReference { return new TextRange(0, 0); } + int colon = nameElement.getText().indexOf(':') + 1; if (myStartTagFlag) { final int parentOffset = ((TreeElement)nameElement).getStartOffsetInParent(); - return new TextRange(parentOffset, parentOffset + nameElement.getTextLength()); - } else { + return new TextRange(parentOffset + colon, parentOffset + nameElement.getTextLength()); + } + else { final PsiElement element = getElement(); - if (element == myNameElement) return new TextRange(0, myNameElement.getTextLength()); + if (element == myNameElement) return new TextRange(colon, myNameElement.getTextLength()); final int elementLength = element.getTextLength(); int diffFromEnd = 0; @@ -91,7 +95,7 @@ public class TagNameReference implements PsiReference { } final int nameEnd = elementLength - diffFromEnd; - return new TextRange(nameEnd - nameElement.getTextLength(), nameEnd); + return new TextRange(nameEnd - nameElement.getTextLength() + colon, nameEnd); } } @@ -175,24 +179,35 @@ public class TagNameReference implements PsiReference { final PsiElement element = getElement(); if(!myStartTagFlag){ if (element instanceof XmlTag) { - return new LookupElement[]{createClosingTagLookupElement((XmlTag)element)}; + return new LookupElement[]{createClosingTagLookupElement((XmlTag)element, false)}; } return ArrayUtil.EMPTY_STRING_ARRAY; } - return getTagNameVariants((XmlTag)element); + return getTagNameVariants((XmlTag)element, ((XmlTag)element).getNamespacePrefix()); } - protected static LookupElement createClosingTagLookupElement(XmlTag tag) { - return TailTypeDecorator.withTail(AutoCompletionPolicy.GIVE_CHANCE_TO_OVERWRITE.applyPolicy(LookupElementBuilder.create(tag.getName())), TailType.createSimpleTailType('>')); + public LookupElement createClosingTagLookupElement(XmlTag tag, boolean includePrefix) { + LookupElementBuilder builder = LookupElementBuilder.create(includePrefix || !myNameElement.getText().contains(":") ? tag.getName() : tag.getLocalName()); + return TailTypeDecorator.withTail(AutoCompletionPolicy.GIVE_CHANCE_TO_OVERWRITE.applyPolicy(builder), + TailType.createSimpleTailType('>')); } + public static LookupElement[] getTagNameVariants(final @NotNull XmlTag tag, final String prefix) { + final List namespaces; + if (prefix.isEmpty()) { + namespaces = new ArrayList(Arrays.asList(tag.knownNamespaces())); + namespaces.add(XmlUtil.EMPTY_URI); // empty namespace + } + else { + namespaces = new ArrayList(Collections.singletonList(tag.getNamespace())); + } + final String[] variants = getTagNameVariants(tag, namespaces, null); + return ContainerUtil.map2Array(variants, LookupElement.class, new Function() { + public LookupElement fun(String qname) { - public static LookupElement[] getTagNameVariants(final XmlTag element) { - final ArrayList namespaces = new ArrayList(Arrays.asList(element.knownNamespaces())); - namespaces.add(XmlUtil.EMPTY_URI); // empty namespace - final String[] variants = getTagNameVariants(element, namespaces, null); - return ContainerUtil.map2Array(variants, MutableLookupElement.class, new Function() { - public MutableLookupElement fun(String qname) { + if (!prefix.isEmpty() && qname.startsWith(prefix)) { + qname = qname.substring(prefix.length() + 1); + } final MutableLookupElement lookupElement = LookupElementFactory.getInstance().createLookupElement(qname); final int separator = qname.indexOf(':'); if (separator > 0) { @@ -249,12 +264,21 @@ public class TagNameReference implements PsiReference { } } - List l = ContainerUtil.mapNotNull(variants, new NullableFunction() { + final boolean hasPrefix = StringUtil.isNotEmpty(element.getNamespacePrefix()); + final List list = ContainerUtil.mapNotNull(variants, new NullableFunction() { public String fun(XmlElementDescriptor descriptor) { - return descriptor instanceof AnyXmlElementDescriptor ? null : descriptor.getName(element); + if (descriptor instanceof AnyXmlElementDescriptor) { + return null; + } + else if (hasPrefix && descriptor instanceof XmlElementDescriptorImpl && + !namespaces.contains(((XmlElementDescriptorImpl)descriptor).getNamespace())) { + return null; + } + + return descriptor.getName(element); } }); - return ArrayUtil.toStringArray(l); + return ArrayUtil.toStringArray(list); } private static void processVariantsInNamespace(final String namespace, @@ -262,14 +286,15 @@ public class TagNameReference implements PsiReference { final List variants, final XmlElementDescriptor elementDescriptor, final String elementNamespace, - final Map descriptorsMap, final Set visited, + final Map descriptorsMap, + final Set visited, XmlTag parent, final XmlExtension extension) { if(descriptorsMap.containsKey(namespace)){ final XmlElementDescriptor descriptor = descriptorsMap.get(namespace); if(isAcceptableNs(element, elementDescriptor, elementNamespace, namespace)){ - for(XmlElementDescriptor containedDescriptor:descriptor.getElementsDescriptors(parent)) { + for(XmlElementDescriptor containedDescriptor: descriptor.getElementsDescriptors(parent)) { if (containedDescriptor != null) variants.add(containedDescriptor); } } @@ -350,7 +375,7 @@ public class TagNameReference implements PsiReference { } @Nullable - public static PsiReference createTagNameReference(XmlElement element, @NotNull ASTNode nameElement, boolean startTagFlag) { + static TagNameReference createTagNameReference(XmlElement element, @NotNull ASTNode nameElement, boolean startTagFlag) { final XmlExtension extension = XmlExtension.getExtensionByElement(element); return extension == null ? null : extension.createTagNameReference(nameElement, startTagFlag); } diff --git a/xml/impl/src/com/intellij/psi/impl/source/xml/XmlAttributeImpl.java b/xml/impl/src/com/intellij/psi/impl/source/xml/XmlAttributeImpl.java index e41e2254961d..cf0b4aa643bd 100644 --- a/xml/impl/src/com/intellij/psi/impl/source/xml/XmlAttributeImpl.java +++ b/xml/impl/src/com/intellij/psi/impl/source/xml/XmlAttributeImpl.java @@ -336,13 +336,13 @@ public class XmlAttributeImpl extends XmlElementImpl implements XmlAttribute { final String prefix = XmlUtil.findPrefixByQualifiedName(getName()); final TextRange range = prefix.length() == 0 ? TextRange.from(getName().length(), 0) : TextRange.from(prefix.length() + 1, localName.length()); - refs[0] = new SchemaPrefixReference(this, range, localName); + refs[0] = new SchemaPrefixReference(this, range, localName, null); } else { final String prefix = getNamespacePrefix(); if (prefix.length() > 0 && getLocalName().length() > 0) { refs = new PsiReference[referencesFromProviders.length + 2]; - refs[0] = new SchemaPrefixReference(this, TextRange.from(0, prefix.length()), prefix); + refs[0] = new SchemaPrefixReference(this, TextRange.from(0, prefix.length()), prefix, null); refs[1] = new MyPsiReference(); } else { diff --git a/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java b/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java index b85b302997f9..00f397913480 100644 --- a/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java +++ b/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java @@ -28,6 +28,7 @@ import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.PomManager; import com.intellij.pom.PomModel; import com.intellij.pom.event.PomModelEvent; @@ -130,17 +131,20 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag { if (startTagName == null) return PsiReference.EMPTY_ARRAY; final ASTNode endTagName = XmlChildRole.CLOSING_TAG_NAME_FINDER.findChild(this); List refs = new ArrayList(); - final String prefix = getNamespacePrefix(); + String prefix = getNamespacePrefix(); + TagNameReference startTagRef = TagNameReference.createTagNameReference(this, startTagName, true); + refs.add(startTagRef); if (prefix.length() > 0) { - refs.add(createPrefixReference(startTagName, prefix)); - if (endTagName != null) { - refs.add(createPrefixReference(endTagName, prefix)); - } + refs.add(createPrefixReference(startTagName, prefix, startTagRef)); } - refs.add(TagNameReference.createTagNameReference(this, startTagName, true)); if (endTagName != null) { - refs.add(TagNameReference.createTagNameReference(this, endTagName, false)); + TagNameReference endTagRef = TagNameReference.createTagNameReference(this, endTagName, false); + refs.add(endTagRef); + prefix = XmlUtil.findPrefixByQualifiedName(endTagName.getText()); + if (StringUtil.isNotEmpty(prefix)) { + refs.add(createPrefixReference(endTagName, prefix, endTagRef)); + } } @@ -153,8 +157,8 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag { return ContainerUtil.toArray(refs, new PsiReference[refs.size()]); } - private SchemaPrefixReference createPrefixReference(ASTNode startTagName, String prefix) { - return new SchemaPrefixReference(this, TextRange.from(startTagName.getStartOffset() - this.getStartOffset(), prefix.length()), prefix); + private SchemaPrefixReference createPrefixReference(ASTNode startTagName, String prefix, TagNameReference tagRef) { + return new SchemaPrefixReference(this, TextRange.from(startTagName.getStartOffset() - this.getStartOffset(), prefix.length()), prefix, tagRef); } public XmlNSDescriptor getNSDescriptor(final String namespace, boolean strict) { diff --git a/xml/impl/src/com/intellij/xml/impl/schema/XmlElementDescriptorImpl.java b/xml/impl/src/com/intellij/xml/impl/schema/XmlElementDescriptorImpl.java index d231ea7cc1c9..f73a36a0754c 100644 --- a/xml/impl/src/com/intellij/xml/impl/schema/XmlElementDescriptorImpl.java +++ b/xml/impl/src/com/intellij/xml/impl/schema/XmlElementDescriptorImpl.java @@ -492,4 +492,9 @@ public class XmlElementDescriptorImpl implements XmlElementDescriptor, PsiWritab } return false; } + + @Override + public String toString() { + return getName() + " (" + getNamespace() + ")"; + } } diff --git a/xml/impl/src/com/intellij/xml/util/XmlUtil.java b/xml/impl/src/com/intellij/xml/util/XmlUtil.java index 4ee3c87690ee..3e803752e185 100644 --- a/xml/impl/src/com/intellij/xml/util/XmlUtil.java +++ b/xml/impl/src/com/intellij/xml/util/XmlUtil.java @@ -953,9 +953,8 @@ public class XmlUtil { private static final String HTML5_SCHEMA_LOCATION; static { - URL schemaLocation = XmlUtil.class.getResource(ExternalResourceManagerImpl.STANDARD_SCHEMAS + "html5/xhtml5.xsd"); - VirtualFile relativeFile = schemaLocation != null ? - VfsUtil.findRelativeFile(VfsUtil.fixURLforIDEA(schemaLocation.toExternalForm()), null):null; + URL schemaLocationURL = XmlUtil.class.getResource(ExternalResourceManagerImpl.STANDARD_SCHEMAS + "html5/xhtml5.xsd"); + VirtualFile relativeFile = schemaLocationURL != null ? VfsUtil.findFileByURL(schemaLocationURL):null; HTML5_SCHEMA_LOCATION = relativeFile != null ? relativeFile.getPath():""; }