mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
better completion logic for macrodef elements
This commit is contained in:
@@ -53,7 +53,7 @@ public class AntDomExtender extends DomExtender<AntDomElement>{
|
||||
TAG_MAPPING.put("dirset", AntDomDirSet.class);
|
||||
TAG_MAPPING.put("filelist", AntDomFileList.class);
|
||||
TAG_MAPPING.put("path", AntDomPath.class);
|
||||
TAG_MAPPING.put("classpath", AntDomPath.class);
|
||||
TAG_MAPPING.put("classpath", AntDomClasspath.class);
|
||||
TAG_MAPPING.put("typedef", AntDomTypeDef.class);
|
||||
TAG_MAPPING.put("taskdef", AntDomTaskdef.class);
|
||||
TAG_MAPPING.put("presetdef", AntDomPresetDef.class);
|
||||
@@ -62,7 +62,6 @@ public class AntDomExtender extends DomExtender<AntDomElement>{
|
||||
TAG_MAPPING.put("antlib", AntDomAntlib.class);
|
||||
TAG_MAPPING.put("ant", AntDomAnt.class);
|
||||
TAG_MAPPING.put("antcall", AntDomAntCall.class);
|
||||
TAG_MAPPING.put("classpath", AntDomClasspath.class);
|
||||
TAG_MAPPING.put("available", AntDomPropertyDefiningTaskWithDefaultValue.class);
|
||||
TAG_MAPPING.put("condition", AntDomPropertyDefiningTaskWithDefaultValue.class);
|
||||
TAG_MAPPING.put("uptodate", AntDomPropertyDefiningTaskWithDefaultValue.class);
|
||||
@@ -100,6 +99,7 @@ public class AntDomExtender extends DomExtender<AntDomElement>{
|
||||
AntIntrospector classBasedIntrospector = null;
|
||||
final Hashtable<String,Class> coreTaskDefs = reflected.getTaskDefinitions();
|
||||
final Hashtable<String, Class> coreTypeDefs = reflected.getDataTypeDefinitions();
|
||||
final boolean isCustom = antDomElement instanceof AntDomCustomElement;
|
||||
if ("project".equals(tagName)) {
|
||||
classBasedIntrospector = getIntrospector(reflected.getProject().getClass());
|
||||
}
|
||||
@@ -107,7 +107,7 @@ public class AntDomExtender extends DomExtender<AntDomElement>{
|
||||
classBasedIntrospector = getIntrospector(reflected.getTargetClass());
|
||||
}
|
||||
else {
|
||||
if (antDomElement instanceof AntDomCustomElement) {
|
||||
if (isCustom) {
|
||||
final AntDomCustomElement custom = (AntDomCustomElement)antDomElement;
|
||||
final Class definitionClass = custom.getDefinitionClass();
|
||||
if (definitionClass != null) {
|
||||
@@ -140,13 +140,13 @@ public class AntDomExtender extends DomExtender<AntDomElement>{
|
||||
parentIntrospector = new ClassIntrospectorAdapter(classBasedIntrospector);
|
||||
}
|
||||
else {
|
||||
if (antDomElement instanceof AntDomCustomElement) {
|
||||
if (isCustom) {
|
||||
final AntDomNamedElement declaringElement = ((AntDomCustomElement)antDomElement).getDeclaringElement();
|
||||
if (declaringElement instanceof AntDomMacroDef) {
|
||||
parentIntrospector = new MacrodefIntrospectorAdapter((AntDomMacroDef)declaringElement);
|
||||
}
|
||||
else if (declaringElement instanceof AntDomMacrodefElement){
|
||||
parentIntrospector = ContainerElementIntrospector.INSTANCE;
|
||||
parentIntrospector = new MacrodefElementOccurrenceIntrospectorAdapter((AntDomMacrodefElement)declaringElement)/*ContainerElementIntrospector.INSTANCE*/;
|
||||
}
|
||||
else if (declaringElement instanceof AntDomScriptDef) {
|
||||
parentIntrospector = new ScriptdefIntrospectorAdapter((AntDomScriptDef)declaringElement);
|
||||
@@ -192,7 +192,7 @@ public class AntDomExtender extends DomExtender<AntDomElement>{
|
||||
final DomExtension extension = registerChild(registrar, genericInfo, nestedElementName);
|
||||
if (extension != null) {
|
||||
Class type = parentIntrospector.getNestedElementType(nestedElementName);
|
||||
if ("java.lang.Object".equals(type.getName())) {
|
||||
if (type != null && "java.lang.Object".equals(type.getName())) {
|
||||
type = null; // hack to support badly written tasks
|
||||
}
|
||||
if (type == null) {
|
||||
@@ -203,13 +203,10 @@ public class AntDomExtender extends DomExtender<AntDomElement>{
|
||||
if (type != null) {
|
||||
extension.putUserData(ELEMENT_IMPL_CLASS_KEY, type);
|
||||
}
|
||||
AntDomElement.Role role = null;
|
||||
AntDomElement.Role role = AntDomElement.Role.DATA_TYPE;
|
||||
if (coreTaskDefs != null && coreTaskDefs.containsKey(nestedElementName)) {
|
||||
role = AntDomElement.Role.TASK;
|
||||
}
|
||||
else if (coreTypeDefs != null && coreTypeDefs.containsKey(nestedElementName)) {
|
||||
role = AntDomElement.Role.DATA_TYPE;
|
||||
}
|
||||
else if (type != null && isAssignableFrom(Task.class.getName(), type)) {
|
||||
role = AntDomElement.Role.TASK;
|
||||
}
|
||||
@@ -502,6 +499,94 @@ public class AntDomExtender extends DomExtender<AntDomElement>{
|
||||
}
|
||||
}
|
||||
|
||||
private static class MacrodefElementOccurrenceIntrospectorAdapter extends AbstractIntrospector {
|
||||
private final AntDomMacrodefElement myElement;
|
||||
private volatile List<AbstractIntrospector> myContexts;
|
||||
private volatile Map<String, Class> myChildrenMap;
|
||||
|
||||
private MacrodefElementOccurrenceIntrospectorAdapter(AntDomMacrodefElement element) {
|
||||
myElement = element;
|
||||
}
|
||||
|
||||
public boolean isContainer() {
|
||||
final List<AbstractIntrospector> contexts = getContexts();
|
||||
for (AbstractIntrospector context : contexts) {
|
||||
if (!context.isContainer()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Iterator<String> getNestedElementsIterator() {
|
||||
return getNestedElementsMap().keySet().iterator();
|
||||
}
|
||||
|
||||
public Class getNestedElementType(String elementName) {
|
||||
return getNestedElementsMap().get(elementName);
|
||||
}
|
||||
|
||||
private Map<String, Class> getNestedElementsMap() {
|
||||
if (myChildrenMap != null) {
|
||||
return myChildrenMap;
|
||||
}
|
||||
final List<AbstractIntrospector> contexts = getContexts();
|
||||
Map<String, Class> names = null;
|
||||
for (AbstractIntrospector context : contexts) {
|
||||
if (context.isContainer()) {
|
||||
continue;
|
||||
}
|
||||
final Set<String> set = new HashSet<String>();
|
||||
for (Iterator<String> it = context.getNestedElementsIterator();it.hasNext();) {
|
||||
final String name = it.next();
|
||||
set.add(name);
|
||||
}
|
||||
if (names == null) {
|
||||
names = new HashMap<String, Class>();
|
||||
for (String s : set) {
|
||||
names.put(s, context.getNestedElementType(s));
|
||||
}
|
||||
}
|
||||
else {
|
||||
names.keySet().retainAll(set);
|
||||
}
|
||||
}
|
||||
final Map<String, Class> result = names == null ? Collections.<String, Class>emptyMap() : names;
|
||||
return myChildrenMap = result;
|
||||
}
|
||||
|
||||
private List<AbstractIntrospector> getContexts() {
|
||||
if (myContexts != null) {
|
||||
return myContexts;
|
||||
}
|
||||
final List<AbstractIntrospector> parents = new ArrayList<AbstractIntrospector>();
|
||||
final AntDomMacroDef macroDef = myElement.getParentOfType(AntDomMacroDef.class, true);
|
||||
if (macroDef != null) {
|
||||
final AntDomSequentialTask body = macroDef.getMacroBody();
|
||||
if (body != null) {
|
||||
body.accept(new AntDomRecursiveVisitor() {
|
||||
public void visitAntDomCustomElement(AntDomCustomElement custom) {
|
||||
if (myElement.equals(custom.getDeclaringElement())) {
|
||||
final AntDomElement parent = custom.getParentOfType(AntDomElement.class, true);
|
||||
if (parent != null) {
|
||||
final Class type = parent.getChildDescription().getUserData(ELEMENT_IMPL_CLASS_KEY);
|
||||
if (type != null) {
|
||||
final AntIntrospector antIntrospector = AntIntrospector.getInstance(type);
|
||||
if (antIntrospector != null) {
|
||||
parents.add(new ClassIntrospectorAdapter(antIntrospector));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return myContexts = parents;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ScriptdefIntrospectorAdapter extends AbstractIntrospector {
|
||||
private final AntDomScriptDef myScriptDef;
|
||||
|
||||
|
||||
@@ -15,10 +15,7 @@
|
||||
*/
|
||||
package com.intellij.lang.ant.dom;
|
||||
|
||||
import com.intellij.util.xml.Attribute;
|
||||
import com.intellij.util.xml.GenericAttributeValue;
|
||||
import com.intellij.util.xml.SubTag;
|
||||
import com.intellij.util.xml.SubTagList;
|
||||
import com.intellij.util.xml.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -38,4 +35,8 @@ public abstract class AntDomMacroDef extends AntDomNamedElement{
|
||||
|
||||
@SubTag("text")
|
||||
public abstract AntDomMacrodefText getTextElement();
|
||||
|
||||
@SubTag("sequential")
|
||||
@Required
|
||||
public abstract AntDomSequentialTask getMacroBody();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.lang.ant.dom;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: Sep 2, 2010
|
||||
*/
|
||||
public abstract class AntDomSequentialTask extends AntDomElement{
|
||||
}
|
||||
@@ -51,7 +51,7 @@ public abstract class AntDomTypeDef extends AntDomCustomClasspathComponent{
|
||||
return CustomAntElementsRegistry.getInstance(getAntProject()).hasTypeLoadingErrors(this);
|
||||
}
|
||||
|
||||
private boolean isTask(final Class clazz) {
|
||||
public boolean isTask(final Class clazz) {
|
||||
if ("taskdef".equals(getXmlTag().getName())) { // in taskdef, the adapter is always set to Task
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -85,13 +85,18 @@ public class CustomAntElementsRegistry {
|
||||
|
||||
@NotNull
|
||||
public Set<XmlName> getCompletionVariants(AntDomElement parentElement) {
|
||||
if (parentElement instanceof AntDomCustomElement) {
|
||||
// this case is already handled in AntDomExtender when defining children
|
||||
return Collections.emptySet();
|
||||
}
|
||||
final Set<XmlName> result = new HashSet<XmlName>();
|
||||
|
||||
final Pair<AntDomMacroDef, AntDomScriptDef> contextMacroOrScriptDef = getContextMacroOrScriptDef(parentElement);
|
||||
final AntDomMacroDef restrictToMacroDef = contextMacroOrScriptDef != null? contextMacroOrScriptDef.getFirst() : null;
|
||||
final AntDomScriptDef restrictToScriptDef = contextMacroOrScriptDef != null? contextMacroOrScriptDef.getSecond() : null;
|
||||
|
||||
for (XmlName xmlName : myCustomElements.keySet()) {
|
||||
final boolean parentIsDataType = parentElement.isDataType();
|
||||
|
||||
for (final XmlName xmlName : myCustomElements.keySet()) {
|
||||
final AntDomNamedElement declaringElement = myDeclarations.get(xmlName);
|
||||
if (declaringElement instanceof AntDomMacrodefElement) {
|
||||
if (restrictToMacroDef == null || !restrictToMacroDef.equals(declaringElement.getParentOfType(AntDomMacroDef.class, true))) {
|
||||
@@ -103,6 +108,25 @@ public class CustomAntElementsRegistry {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (declaringElement != null) {
|
||||
if (declaringElement.equals(restrictToMacroDef) || declaringElement.equals(restrictToScriptDef)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (parentIsDataType) {
|
||||
if (declaringElement instanceof AntDomMacroDef || declaringElement instanceof AntDomScriptDef || declaringElement instanceof AntDomTaskdef) {
|
||||
continue;
|
||||
}
|
||||
if (declaringElement instanceof AntDomTypeDef) {
|
||||
final AntDomTypeDef typedef = (AntDomTypeDef)declaringElement;
|
||||
final Class clazz = myCustomElements.get(xmlName);
|
||||
if (clazz != null && typedef.isTask(clazz)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.add(xmlName);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user