Merge branch 'master' of git.labs.intellij.net:idea/community

This commit is contained in:
irengrig
2010-07-14 16:44:31 +04:00
28 changed files with 269 additions and 131 deletions
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -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()
@@ -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<TIntHashSet> mySourcesToRecompile = new TIntObjectHashMap<TIntHashSet>(); // ProjectId->set of source file paths
private PersistentHashMap<Integer, TIntObjectHashMap<Pair<Integer, Integer>>> myOutputRootsStorage; // ProjectId->map[moduleId->Pair(outputDirId, testOutputDirId)]
private final TIntObjectHashMap<Map<String, SourceUrlClassNamePair>> myOutputsToDelete = new TIntObjectHashMap<Map<String, SourceUrlClassNamePair>>(); // 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<VirtualFile> selectedForRecompilation = new HashSet<VirtualFile>();
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<String, SourceUrlClassNamePair> 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);
}
@@ -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) {
@@ -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);
@@ -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();
}
@@ -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() {
@@ -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<IntentionAction> list = myFixture.filterAvailableIntentions(hint);
if (intentionExists) {
@@ -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);
}
}
@@ -0,0 +1,10 @@
[].ea<caret>ch {
if (it == 2) {
println 2
}
if (it == 3) {
println { String s ->
println s
}
}
}
@@ -0,0 +1,10 @@
for (it in []) {
if (it == 2) {
println 2
}
if (it == 3) {
println { String s ->
println s
}
}
}
@@ -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<ZenCodingFilter> filters = getFilters(node, context);
List<GenerationNode> genNodes = node.expand(-1);
List<GenerationNode> 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
@@ -42,14 +42,11 @@ public class AddOperationNode extends ZenCodingNode {
@NotNull
@Override
public List<GenerationNode> expand(int numberInIteration) {
public List<GenerationNode> expand(int numberInIteration, String surroundedText) {
List<GenerationNode> result = new ArrayList<GenerationNode>();
List<GenerationNode> leftNodes = myLeftOperand.expand(numberInIteration);
for (GenerationNode leftNode : leftNodes) {
leftNode.setToInsertChildren(false);
}
List<GenerationNode> leftNodes = myLeftOperand.expand(numberInIteration, null);
result.addAll(leftNodes);
result.addAll(myRightOperand.expand(numberInIteration));
result.addAll(myRightOperand.expand(numberInIteration, surroundedText));
return result;
}
}
@@ -41,7 +41,7 @@ public class FilterNode extends ZenCodingNode {
@NotNull
@Override
public List<GenerationNode> expand(int numberInIteration) {
return myNode.expand(numberInIteration);
public List<GenerationNode> expand(int numberInIteration, String surroundedText) {
return myNode.expand(numberInIteration, surroundedText);
}
}
@@ -56,16 +56,13 @@ public class GenerationNode {
private final TemplateToken myTemplateToken;
private final List<GenerationNode> myChildren;
private final int myNumberInIteration;
private boolean myToInsertChildren = true;
private final String mySurroundedText;
public GenerationNode(TemplateToken templateToken, List<GenerationNode> children, int numberInIteration) {
public GenerationNode(TemplateToken templateToken, List<GenerationNode> children, int numberInIteration, String surroundedText) {
myTemplateToken = templateToken;
myChildren = children;
myNumberInIteration = numberInIteration;
}
public void setToInsertChildren(boolean toInsertChildren) {
myToInsertChildren = toInsertChildren;
mySurroundedText = surroundedText;
}
public List<GenerationNode> getChildren() {
@@ -73,11 +70,6 @@ public class GenerationNode {
}
public void addChildren(Collection<GenerationNode> 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<ZenCodingFilter> filters) {
GenerationNode generationNode = this;
@@ -114,14 +101,14 @@ public class GenerationNode {
}
if (generationNode != this) {
return generationNode.generate(callback, surroundedText, generator, Collections.<ZenCodingFilter>emptyList());
return generationNode.generate(callback, generator, Collections.<ZenCodingFilter>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<String, String> 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();
@@ -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<GenerationNode> children) {
if (!root.isToInsertChildren()) {
return;
}
if (root.isLeaf()) {
root.addChildren(children);
}
@@ -57,25 +55,37 @@ public class MoreOperationNode extends ZenCodingNode {
@NotNull
@Override
public List<GenerationNode> expand(int numberInIteration) {
if (myLeftOperand instanceof MulOperationNode) {
MulOperationNode mul = (MulOperationNode)myLeftOperand;
ZenCodingNode node = mul.getLeftOperand();
int count = mul.getRightOperand();
public List<GenerationNode> expand(int numberInIteration, String surroundedText) {
if (myLeftOperand instanceof MulOperationNode || (myLeftOperand instanceof UnaryMulOperationNode && surroundedText != null)) {
List<GenerationNode> result = new ArrayList<GenerationNode>();
for (int i = 0; i < count; i++) {
List<GenerationNode> parentNodes = node.expand(i);
List<GenerationNode> 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<GenerationNode> parentNodes = mul.getLeftOperand().expand(i, surroundedText);
List<GenerationNode> 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<GenerationNode> parentNodes = unaryMul.getOperand().expand(i, lines[i]);
List<GenerationNode> innerNodes = myRightOperand.expand(i, lines[i]);
for (GenerationNode parentNode : parentNodes) {
addChildrenToAllLeafs(parentNode, innerNodes);
}
result.addAll(parentNodes);
}
result.addAll(parentNodes);
}
return result;
}
List<GenerationNode> leftGenNodes = myLeftOperand.expand(numberInIteration);
List<GenerationNode> leftGenNodes = myLeftOperand.expand(numberInIteration, surroundedText);
for (GenerationNode leftGenNode : leftGenNodes) {
List<GenerationNode> rightGenNodes = myRightOperand.expand(numberInIteration);
List<GenerationNode> rightGenNodes = myRightOperand.expand(numberInIteration, surroundedText);
addChildrenToAllLeafs(leftGenNode, rightGenNodes);
}
return leftGenNodes;
@@ -42,10 +42,10 @@ public class MulOperationNode extends ZenCodingNode {
@NotNull
@Override
public List<GenerationNode> expand(int numberInIteration) {
public List<GenerationNode> expand(int numberInIteration, String surroundedText) {
List<GenerationNode> result = new ArrayList<GenerationNode>();
for (int i = 0; i < myRightOperand; i++) {
result.addAll(myLeftOperand.expand(i));
result.addAll(myLeftOperand.expand(i, surroundedText));
}
return result;
}
@@ -38,7 +38,8 @@ public class TemplateNode extends ZenCodingNode {
@NotNull
@Override
public List<GenerationNode> expand(int numberInIteration) {
return Arrays.asList(new GenerationNode(myTemplateToken, new ArrayList<GenerationNode>(), numberInIteration));
public List<GenerationNode> expand(int numberInIteration, String surroundedText) {
GenerationNode node = new GenerationNode(myTemplateToken, new ArrayList<GenerationNode>(), numberInIteration, surroundedText);
return Arrays.asList(node);
}
}
@@ -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<GenerationNode> expand(int numberInIteration, String surroundedText) {
if (surroundedText == null) {
return myOperand.expand(numberInIteration, surroundedText);
}
String[] lines = LineTokenizer.tokenize(surroundedText, false);
List<GenerationNode> result = new ArrayList<GenerationNode>();
for (int i = 0; i < lines.length; i++) {
result.addAll(myOperand.expand(i, lines[i]));
}
return result;
}
}
@@ -24,5 +24,5 @@ import java.util.List;
*/
public abstract class ZenCodingNode {
@NotNull
public abstract List<GenerationNode> expand(int numberInIteration);
public abstract List<GenerationNode> expand(int numberInIteration, String surroundedText);
}
@@ -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;
@@ -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<XmlElement> {
};
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<XmlElement> {
@NotNull
public Object[] getVariants() {
if (myTagNameReference != null) {
return new LookupElement[]{ myTagNameReference.createClosingTagLookupElement(myTagNameReference.getTagElement(), true)};
}
return ArrayUtil.EMPTY_OBJECT_ARRAY;
}
@@ -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<String> namespaces;
if (prefix.isEmpty()) {
namespaces = new ArrayList<String>(Arrays.asList(tag.knownNamespaces()));
namespaces.add(XmlUtil.EMPTY_URI); // empty namespace
}
else {
namespaces = new ArrayList<String>(Collections.singletonList(tag.getNamespace()));
}
final String[] variants = getTagNameVariants(tag, namespaces, null);
return ContainerUtil.map2Array(variants, LookupElement.class, new Function<String, LookupElement>() {
public LookupElement fun(String qname) {
public static LookupElement[] getTagNameVariants(final XmlTag element) {
final ArrayList<String> namespaces = new ArrayList<String>(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<String, MutableLookupElement>() {
public MutableLookupElement fun(String qname) {
if (!prefix.isEmpty() && qname.startsWith(prefix)) {
qname = qname.substring(prefix.length() + 1);
}
final MutableLookupElement<String> lookupElement = LookupElementFactory.getInstance().createLookupElement(qname);
final int separator = qname.indexOf(':');
if (separator > 0) {
@@ -249,12 +264,21 @@ public class TagNameReference implements PsiReference {
}
}
List<String> l = ContainerUtil.mapNotNull(variants, new NullableFunction<XmlElementDescriptor, String>() {
final boolean hasPrefix = StringUtil.isNotEmpty(element.getNamespacePrefix());
final List<String> list = ContainerUtil.mapNotNull(variants, new NullableFunction<XmlElementDescriptor, String>() {
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<XmlElementDescriptor> variants,
final XmlElementDescriptor elementDescriptor,
final String elementNamespace,
final Map<String, XmlElementDescriptor> descriptorsMap, final Set<XmlNSDescriptor> visited,
final Map<String, XmlElementDescriptor> descriptorsMap,
final Set<XmlNSDescriptor> 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);
}
@@ -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 {
@@ -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<PsiReference> refs = new ArrayList<PsiReference>();
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) {
@@ -492,4 +492,9 @@ public class XmlElementDescriptorImpl implements XmlElementDescriptor, PsiWritab
}
return false;
}
@Override
public String toString() {
return getName() + " (" + getNamespace() + ")";
}
}
@@ -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():"";
}