mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-102173 Android XML: automatically insert app-level namespace when complete custom attrs instead of inserting it without an prefix
This commit is contained in:
@@ -20,11 +20,11 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.xml.XmlElement;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.util.xml.XmlName;
|
||||
import com.intellij.util.xml.impl.DomInvocationHandler;
|
||||
import com.intellij.util.xml.impl.DomManagerImpl;
|
||||
import com.intellij.util.xml.reflect.DomAttributeChildDescription;
|
||||
import com.intellij.util.xml.XmlName;
|
||||
import com.intellij.xml.XmlAttributeDescriptor;
|
||||
import com.intellij.xml.NamespaceAwareXmlAttributeDescriptor;
|
||||
import com.intellij.xml.util.XmlUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -32,7 +32,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
/**
|
||||
* @author mike
|
||||
*/
|
||||
public class DomAttributeXmlDescriptor implements XmlAttributeDescriptor {
|
||||
public class DomAttributeXmlDescriptor implements NamespaceAwareXmlAttributeDescriptor {
|
||||
private final DomAttributeChildDescription myDescription;
|
||||
private final Project myProject;
|
||||
|
||||
@@ -114,6 +114,11 @@ public class DomAttributeXmlDescriptor implements XmlAttributeDescriptor {
|
||||
return myDescription.getXmlName().getLocalName();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getNamespace() {
|
||||
return myDescription.getXmlName().getNamespaceKey();
|
||||
}
|
||||
|
||||
public void init(final PsiElement element) {
|
||||
throw new UnsupportedOperationException("Method init not implemented in " + getClass());
|
||||
}
|
||||
|
||||
@@ -21,10 +21,16 @@ import com.intellij.lang.html.HTMLLanguage;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.ScrollType;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import com.intellij.xml.XmlNamespaceHelper;
|
||||
import com.intellij.xml.util.HtmlUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
@@ -32,6 +38,18 @@ import com.intellij.xml.util.HtmlUtil;
|
||||
public class XmlAttributeInsertHandler implements InsertHandler<LookupElement> {
|
||||
public static final XmlAttributeInsertHandler INSTANCE = new XmlAttributeInsertHandler();
|
||||
|
||||
private final String myNamespacePrefixToInsert;
|
||||
private final String myNamespaceToInsert;
|
||||
|
||||
public XmlAttributeInsertHandler() {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
public XmlAttributeInsertHandler(@Nullable String namespaceToInsert, @Nullable String namespacePrefixToInsert) {
|
||||
myNamespaceToInsert = namespaceToInsert;
|
||||
myNamespacePrefixToInsert = namespacePrefixToInsert;
|
||||
}
|
||||
|
||||
public void handleInsert(InsertionContext context, LookupElement item) {
|
||||
final Editor editor = context.getEditor();
|
||||
|
||||
@@ -68,5 +86,15 @@ public class XmlAttributeInsertHandler implements InsertHandler<LookupElement> {
|
||||
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
|
||||
editor.getSelectionModel().removeSelection();
|
||||
AutoPopupController.getInstance(editor.getProject()).scheduleAutoPopup(editor);
|
||||
|
||||
if (myNamespaceToInsert != null && file instanceof XmlFile) {
|
||||
final XmlNamespaceHelper helper = XmlNamespaceHelper.getHelper(context.getFile());
|
||||
|
||||
if (helper != null) {
|
||||
PsiDocumentManager.getInstance(context.getProject()).commitDocument(document);
|
||||
helper.insertNamespaceDeclaration((XmlFile)file, editor, Collections.singleton(myNamespaceToInsert),
|
||||
myNamespacePrefixToInsert, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+42
-2
@@ -18,13 +18,16 @@ package com.intellij.codeInsight.completion;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.impl.source.xml.XmlAttributeImpl;
|
||||
import com.intellij.psi.impl.source.xml.XmlAttributeReference;
|
||||
import com.intellij.psi.meta.PsiPresentableMetaData;
|
||||
import com.intellij.psi.xml.XmlAttribute;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.intellij.xml.NamespaceAwareXmlAttributeDescriptor;
|
||||
import com.intellij.xml.XmlAttributeDescriptor;
|
||||
import com.intellij.xml.XmlElementDescriptor;
|
||||
import com.intellij.xml.XmlExtension;
|
||||
@@ -68,7 +71,8 @@ public class XmlAttributeReferenceCompletionProvider extends CompletionProvider<
|
||||
XmlAttribute attribute,
|
||||
@Nullable InsertHandler<LookupElement> replacementInsertHandler) {
|
||||
final XmlTag tag = attribute.getParent();
|
||||
final XmlExtension extension = XmlExtension.getExtension(tag.getContainingFile());
|
||||
final PsiFile file = tag.getContainingFile();
|
||||
final XmlExtension extension = XmlExtension.getExtension(file);
|
||||
final String prefix = attribute.getName().contains(":") && ((XmlAttributeImpl) attribute).getRealLocalName().length() > 0
|
||||
? attribute.getNamespacePrefix() + ":"
|
||||
: null;
|
||||
@@ -80,6 +84,29 @@ public class XmlAttributeReferenceCompletionProvider extends CompletionProvider<
|
||||
for (XmlAttributeDescriptor descriptor : descriptors) {
|
||||
if (isValidVariant(attribute, descriptor, attributes, extension)) {
|
||||
String name = descriptor.getName(tag);
|
||||
|
||||
InsertHandler<LookupElement> insertHandler = XmlAttributeInsertHandler.INSTANCE;
|
||||
|
||||
if (replacementInsertHandler != null) {
|
||||
insertHandler = replacementInsertHandler;
|
||||
}
|
||||
else if (descriptor instanceof NamespaceAwareXmlAttributeDescriptor) {
|
||||
final String namespace = ((NamespaceAwareXmlAttributeDescriptor)descriptor).getNamespace();
|
||||
|
||||
if (file instanceof XmlFile &&
|
||||
namespace != null &&
|
||||
namespace.length() > 0 &&
|
||||
!name.contains(":") &&
|
||||
tag.getPrefixByNamespace(namespace) == null) {
|
||||
String suggestedPrefix = ExtendedTagInsertHandler.suggestPrefix((XmlFile)file, namespace);
|
||||
|
||||
if (suggestedPrefix != null) {
|
||||
suggestedPrefix = makePrefixUnique(suggestedPrefix, tag);
|
||||
name = suggestedPrefix + ":" + name;
|
||||
insertHandler = new XmlAttributeInsertHandler(namespace, suggestedPrefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (prefix == null || name.startsWith(prefix)) {
|
||||
if (prefix != null && name.length() > prefix.length()) {
|
||||
name = descriptor.getName(tag).substring(prefix.length());
|
||||
@@ -94,7 +121,7 @@ public class XmlAttributeReferenceCompletionProvider extends CompletionProvider<
|
||||
}
|
||||
element = element
|
||||
.withCaseSensitivity(caseSensitive)
|
||||
.withInsertHandler(replacementInsertHandler != null ? replacementInsertHandler : XmlAttributeInsertHandler.INSTANCE);
|
||||
.withInsertHandler(insertHandler);
|
||||
result.addElement(
|
||||
descriptor.isRequired() ? PrioritizedLookupElement.withPriority(element.appendTailText("(required)", true), 100) : element);
|
||||
}
|
||||
@@ -102,6 +129,19 @@ public class XmlAttributeReferenceCompletionProvider extends CompletionProvider<
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String makePrefixUnique(@NotNull String basePrefix, @NotNull XmlTag context) {
|
||||
if (context.getNamespaceByPrefix(basePrefix).isEmpty()) {
|
||||
return basePrefix;
|
||||
}
|
||||
int i = 1;
|
||||
|
||||
while (!context.getNamespaceByPrefix(basePrefix + i).isEmpty()) {
|
||||
i++;
|
||||
}
|
||||
return basePrefix + i;
|
||||
}
|
||||
|
||||
private static boolean isValidVariant(XmlAttribute attribute,
|
||||
@NotNull XmlAttributeDescriptor descriptor,
|
||||
final XmlAttribute[] attributes,
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.intellij.xml;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public interface NamespaceAwareXmlAttributeDescriptor extends XmlAttributeDescriptor {
|
||||
@Nullable
|
||||
String getNamespace();
|
||||
}
|
||||
Reference in New Issue
Block a user