Re-enact changes in tag synchronizer

GitOrigin-RevId: a9ab3767a8999fbd542d43c509099e99406e8860
This commit is contained in:
Kirill Glazyrin
2020-02-15 11:37:44 +00:00
committed by intellij-monorepo-bot
parent 48425cb580
commit c29e62ae5d
5 changed files with 91 additions and 21 deletions
@@ -16,6 +16,7 @@
package com.intellij.psi.templateLanguages;
import com.intellij.lang.ASTNode;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
@@ -53,4 +54,22 @@ public class TemplateLanguageUtil {
return viewProvider instanceof TemplateLanguageFileViewProvider &&
file == viewProvider.getPsi(((TemplateLanguageFileViewProvider)viewProvider).getTemplateDataLanguage());
}
@Nullable
public static ASTNode getSameLanguageTreePrev(@NotNull ASTNode node) {
ASTNode current = node.getTreePrev();
while (current instanceof OuterLanguageElement) {
current = current.getTreePrev();
}
return current;
}
@Nullable
public static ASTNode getSameLanguageTreeNext(@NotNull ASTNode node) {
ASTNode current = node.getTreeNext();
while (current instanceof OuterLanguageElement) {
current = current.getTreeNext();
}
return current;
}
}
@@ -26,6 +26,7 @@ import com.intellij.openapi.util.TextRange;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.templateLanguages.TemplateLanguageUtil;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlChildRole;
@@ -127,12 +128,12 @@ public class XmlTagTreeHighlightingPass extends TextEditorHighlightingPass {
return null;
}
ASTNode tagName = startTagStart.getTreeNext();
ASTNode tagName = TemplateLanguageUtil.getSameLanguageTreeNext(startTagStart);
if (tagName == null || (tagName.getElementType() != XmlTokenType.XML_NAME && tagName.getElementType() != XmlTokenType.XML_TAG_NAME)) {
return null;
}
ASTNode next = tagName.getTreeNext();
ASTNode next = TemplateLanguageUtil.getSameLanguageTreeNext(tagName);
if (next != null && next.getElementType() == XmlTokenType.XML_TAG_END) {
tagName = next;
}
@@ -149,7 +150,7 @@ public class XmlTagTreeHighlightingPass extends TextEditorHighlightingPass {
ASTNode endTagEnd = endTagStart;
while (endTagEnd != null && endTagEnd.getElementType() != XmlTokenType.XML_TAG_END) {
endTagEnd = endTagEnd.getTreeNext();
endTagEnd = TemplateLanguageUtil.getSameLanguageTreeNext(endTagEnd);
}
if (endTagEnd == null) {
@@ -28,19 +28,21 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.core.impl.PomModelImpl;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiDocumentManagerBase;
import com.intellij.psi.impl.source.tree.TreeUtil;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.templateLanguages.OuterLanguageElement;
import com.intellij.psi.templateLanguages.TemplateLanguage;
import com.intellij.psi.xml.XmlTokenType;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.xml.XmlExtension;
import com.intellij.xml.util.HtmlUtil;
import com.intellij.xml.util.XmlUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.Set;
@@ -118,12 +120,15 @@ public final class XmlTagNameSynchronizer implements CommandListener, EditorFact
private final PsiDocumentManagerBase myDocumentManager;
private final Language myLanguage;
private final EditorImpl myEditor;
private final Project myProject;
private XmlExtension myExtension;
private boolean myApplying;
private TagNameSynchronizer(EditorImpl editor, Project project, Language language) {
myEditor = editor;
myLanguage = language;
myDocumentManager = (PsiDocumentManagerBase)PsiDocumentManager.getInstance(project);
myProject = project;
}
private void listenForDocumentChanges() {
@@ -159,7 +164,7 @@ public final class XmlTagNameSynchronizer implements CommandListener, EditorFact
Caret caret = myEditor.getCaretModel().getCurrentCaret();
for (int i = 0; i < newLength; i++) {
if (!XmlUtil.isValidTagNameChar(fragment.charAt(i))) {
if (!isValidTagNameChar(fragment.charAt(i))) {
clearMarkers(caret);
return;
}
@@ -220,7 +225,7 @@ public final class XmlTagNameSynchronizer implements CommandListener, EditorFact
start = i + 1;
break;
}
if (!XmlUtil.isValidTagNameChar(c)) break;
if (!isValidTagNameChar(c)) break;
seenColon |= c == ':';
}
catch (IndexOutOfBoundsException e) {
@@ -232,7 +237,7 @@ public final class XmlTagNameSynchronizer implements CommandListener, EditorFact
int end = -1;
for (int i = offset; i < Math.min(document.getTextLength(), offset + 50); i++) {
final char c = sequence.charAt(i);
if (!XmlUtil.isValidTagNameChar(c) || seenColon && c == ':') {
if (!isValidTagNameChar(c) || seenColon && c == ':') {
end = i;
break;
}
@@ -284,19 +289,32 @@ public final class XmlTagNameSynchronizer implements CommandListener, EditorFact
}
private RangeMarker findSupport(RangeMarker leader, PsiFile file, Document document) {
final TextRange leaderRange = new TextRange(leader.getStartOffset(), leader.getEndOffset());
final int offset = leader.getStartOffset();
PsiElement element = InjectedLanguageUtil.findElementAtNoCommit(file, offset);
PsiElement support = findSupportElement(element);
if (support == null && file.getViewProvider() instanceof MultiplePsiFilesPerDocumentFileViewProvider) {
TextRange support = findSupportRange(element);
if (!isSupportRangeValid(document, leaderRange, support) && file.getViewProvider() instanceof MultiplePsiFilesPerDocumentFileViewProvider) {
element = file.getViewProvider().findElementAt(offset, myLanguage);
support = findSupportElement(element);
support = findSupportRange(element);
}
if (support == null) return findSupportForTagList(leader, element, document);
if (!isSupportRangeValid(document, leaderRange, support)) return findSupportForTagList(leader, element, document);
return document.createRangeMarker(support.getStartOffset(), support.getEndOffset(), true);
}
final TextRange range = support.getTextRange();
TextRange realRange = InjectedLanguageManager.getInstance(file.getProject()).injectedToHost(element.getContainingFile(), range);
return document.createRangeMarker(realRange.getStartOffset(), realRange.getEndOffset(), true);
private boolean isValidTagNameChar(char c) {
if (myExtension == null) initXmlExtension();
return XmlUtil.isValidTagNameChar(c) || myExtension.isValidTagNameChar(c);
}
private void initXmlExtension() {
Document document = myEditor.getDocument();
VirtualFile file = FileDocumentManager.getInstance().getFile(document);
PsiFile psiFile = file != null && file.isValid() ? PsiManager.getInstance(myProject).findFile(file) : null;
if (psiFile == null) {
return;
}
myExtension = XmlExtension.getExtension(psiFile);
}
private static RangeMarker findSupportForTagList(RangeMarker leader, PsiElement element, Document document) {
@@ -322,11 +340,39 @@ public final class XmlTagNameSynchronizer implements CommandListener, EditorFact
return null;
}
private static PsiElement findSupportElement(PsiElement element) {
if (element == null || TreeUtil.findSibling(element.getNode(), XmlTokenType.XML_TAG_END) == null) return null;
PsiElement support = RenameTagBeginOrEndIntentionAction.findOtherSide(element, false);
support = support == null || element == support ? RenameTagBeginOrEndIntentionAction.findOtherSide(element, true) : support;
return support != null && StringUtil.equals(element.getText(), support.getText()) ? support : null;
private static boolean isSupportRangeValid(@NotNull Document document, @NotNull TextRange leader, @Nullable TextRange support) {
if (support == null) return false;
return document.getText(leader).equals(document.getText(support));
}
@Nullable
private static TextRange findSupportRange(@Nullable PsiElement leader) {
if (leader == null || TreeUtil.findSibling(leader.getNode(), XmlTokenType.XML_TAG_END) == null) return null;
PsiElement support = RenameTagBeginOrEndIntentionAction.findOtherSide(leader, false);
if (support == null || leader == support) support = RenameTagBeginOrEndIntentionAction.findOtherSide(leader, true);
if (support == null) return null;
final int start = findSupportRangeStart(support);
final int end = findSupportRangeEnd(support);
final TextRange supportRange = TextRange.create(start, end);
return InjectedLanguageManager.getInstance(leader.getProject()).injectedToHost(leader.getContainingFile(), supportRange);
}
private static int findSupportRangeStart(@NotNull PsiElement support) {
PsiElement current = support;
while (current.getPrevSibling() instanceof OuterLanguageElement) {
current = current.getPrevSibling();
}
return current.getTextRange().getStartOffset();
}
private static int findSupportRangeEnd(@NotNull PsiElement support) {
PsiElement current = support;
while (current.getNextSibling() instanceof OuterLanguageElement) {
current = current.getNextSibling();
}
return current.getTextRange().getEndOffset();
}
}
}
@@ -5,6 +5,7 @@ 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.templateLanguages.TemplateLanguageUtil;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.xml.XmlTag;
import com.intellij.psi.xml.XmlTagValue;
@@ -123,8 +124,7 @@ public class XmlTagUtil extends XmlTagUtilBase {
}
prev = current;
current = current.getTreePrev();
current = TemplateLanguageUtil.getSameLanguageTreePrev(current);
}
return null;
}
@@ -208,6 +208,10 @@ public abstract class XmlExtension {
public boolean isSingleTagException(@NotNull XmlTag tag) { return false; }
public boolean isValidTagNameChar(final char c) {
return false;
}
public static boolean shouldIgnoreSelfClosingTag(@NotNull XmlTag tag) {
final XmlExtension extension = getExtensionByElement(tag);
return extension != null && extension.isSelfClosingTagAllowed(tag);