blob: 3e52b819c28512540488f68b48e9bd986e7cea69 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.completion;
import com.intellij.codeInsight.AutoPopupController;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.lang.html.HTMLLanguage;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.text.CharArrayUtil;
import com.intellij.xml.XmlNamespaceHelper;
import com.intellij.xml.util.HtmlUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
/**
* @author peter
*/
public class XmlAttributeInsertHandler implements InsertHandler<LookupElement> {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.XmlAttributeInsertHandler");
public static final XmlAttributeInsertHandler INSTANCE = new XmlAttributeInsertHandler();
private final String myNamespaceToInsert;
public XmlAttributeInsertHandler() {
this(null);
}
public XmlAttributeInsertHandler(@Nullable String namespaceToInsert) {
myNamespaceToInsert = namespaceToInsert;
}
@Override
public void handleInsert(final InsertionContext context, final LookupElement item) {
final Editor editor = context.getEditor();
final Document document = editor.getDocument();
final int caretOffset = editor.getCaretModel().getOffset();
final PsiFile file = context.getFile();
if (file.getLanguage() == HTMLLanguage.INSTANCE &&
HtmlUtil.isSingleHtmlAttribute((String)item.getObject())) {
return;
}
final CharSequence chars = document.getCharsSequence();
if (!CharArrayUtil.regionMatches(chars, caretOffset, "=\"") && !CharArrayUtil.regionMatches(chars, caretOffset, "='")) {
PsiElement fileContext = file.getContext();
String toInsert= "=\"\"";
if(fileContext != null) {
if (fileContext.getText().startsWith("\"")) toInsert = "=''";
}
if (caretOffset >= document.getTextLength() || "/> \n\t\r".indexOf(document.getCharsSequence().charAt(caretOffset)) < 0) {
document.insertString(caretOffset, toInsert + " ");
}
else {
document.insertString(caretOffset, toInsert);
}
if ('=' == context.getCompletionChar()) {
context.setAddCompletionChar(false); // IDEA-19449
}
}
editor.getCaretModel().moveToOffset(caretOffset + 2);
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
editor.getSelectionModel().removeSelection();
AutoPopupController.getInstance(editor.getProject()).scheduleAutoPopup(editor);
if (myNamespaceToInsert != null && file instanceof XmlFile) {
final PsiElement element = file.findElementAt(context.getStartOffset());
final XmlTag tag = element != null ? PsiTreeUtil.getParentOfType(element, XmlTag.class) : null;
if (tag != null) {
String prefix = ExtendedTagInsertHandler.suggestPrefix((XmlFile)file, myNamespaceToInsert);
if (prefix != null) {
prefix = makePrefixUnique(prefix, tag);
final XmlNamespaceHelper helper = XmlNamespaceHelper.getHelper(context.getFile());
if (helper != null) {
final Project project = context.getProject();
PsiDocumentManager.getInstance(project).commitDocument(document);
qualifyWithPrefix(prefix, element);
helper.insertNamespaceDeclaration((XmlFile)file, editor, Collections.singleton(
myNamespaceToInsert), prefix, null);
}
}
}
}
}
private static void qualifyWithPrefix(@NotNull String namespacePrefix, @NotNull PsiElement context) {
final PsiElement parent = context.getParent();
if (parent instanceof XmlAttribute) {
final XmlAttribute attribute = (XmlAttribute)parent;
final String prefix = attribute.getNamespacePrefix();
if (!prefix.equals(namespacePrefix) && StringUtil.isNotEmpty(namespacePrefix)) {
final String name = namespacePrefix + ":" + attribute.getLocalName();
try {
attribute.setName(name);
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
}
}
@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;
}
}