@Override public LazyParseableElement createLazy(ILazyParseableElementType type, CharSequence text) { if (type == XML_FILE) { return new XmlFileElement(type, text); } else if (type == DTD_FILE) { return new XmlFileElement(type, text); } else if (type == XHTML_FILE) { return new XmlFileElement(type, text); } else if (type == HTML_FILE) { return new HtmlFileElement(text); } else if (type instanceof ITemplateDataElementType) { return new XmlFileElement(type, text); } return null; }
/** * This method searches ast node that could be reparsed incrementally and returns pair of target reparseable node and new replacement node. * Returns null if there is no any chance to make incremental parsing. */ @Nullable public Couple<ASTNode> findReparseableRoots(@NotNull PsiFileImpl file, @NotNull TextRange changedPsiRange, @NotNull CharSequence newFileText) { Project project = file.getProject(); final FileElement fileElement = file.getTreeElement(); final CharTable charTable = fileElement.getCharTable(); int lengthShift = newFileText.length() - fileElement.getTextLength(); if (fileElement.getElementType() instanceof ITemplateDataElementType || isTooDeep(file)) { // unable to perform incremental reparse for template data in JSP, or in exceptionally deep trees return null; } final ASTNode leafAtStart = fileElement.findLeafElementAt(Math.max(0, changedPsiRange.getStartOffset() - 1)); final ASTNode leafAtEnd = fileElement.findLeafElementAt(Math.min(changedPsiRange.getEndOffset(), fileElement.getTextLength() - 1)); ASTNode node = leafAtStart != null && leafAtEnd != null ? TreeUtil.findCommonParent(leafAtStart, leafAtEnd) : fileElement; Language baseLanguage = file.getViewProvider().getBaseLanguage(); while (node != null && !(node instanceof FileElement)) { IElementType elementType = node.getElementType(); if (elementType instanceof IReparseableElementType) { final TextRange textRange = node.getTextRange(); final IReparseableElementType reparseable = (IReparseableElementType)elementType; if (baseLanguage.isKindOf(reparseable.getLanguage()) && textRange.getLength() + lengthShift > 0) { final int start = textRange.getStartOffset(); final int end = start + textRange.getLength() + lengthShift; if (end > newFileText.length()) { reportInconsistentLength(file, newFileText, node, start, end); break; } CharSequence newTextStr = newFileText.subSequence(start, end); if (reparseable.isParsable(node.getTreeParent(), newTextStr, baseLanguage, project)) { ASTNode chameleon = reparseable.createNode(newTextStr); if (chameleon != null) { DummyHolder holder = DummyHolderFactory.createHolder(file.getManager(), null, node.getPsi(), charTable); holder.getTreeElement().rawAddChildren((TreeElement)chameleon); if (holder.getTextLength() != newTextStr.length()) { String details = ApplicationManager.getApplication().isInternal() ? "text=" + newTextStr + "; treeText=" + holder.getText() + ";" : ""; LOG.error("Inconsistent reparse: " + details + " type=" + elementType); } return Couple.of(node, chameleon); } } } } node = node.getTreeParent(); } return null; }
@Override public CompositeElement createComposite(final IElementType type) { if (type == XML_TAG) { return new XmlTagImpl(); } else if (type == XML_CONDITIONAL_SECTION) { return new XmlConditionalSectionImpl(); } else if (type == HTML_TAG) { return new HtmlTagImpl(); } else if (type == XML_TEXT) { return new XmlTextImpl(); } else if (type == XML_PROCESSING_INSTRUCTION) { return new XmlProcessingInstructionImpl(); } else if (type == XML_DOCUMENT) { return new XmlDocumentImpl(); } else if (type == HTML_DOCUMENT) { return new HtmlDocumentImpl(); } else if (type == XML_PROLOG) { return new XmlPrologImpl(); } else if (type == XML_DECL) { return new XmlDeclImpl(); } else if (type == XML_ATTRIBUTE) { return new XmlAttributeImpl(); } else if (type == XML_ATTRIBUTE_VALUE) { return new XmlAttributeValueImpl(); } else if (type == XML_COMMENT) { return new XmlCommentImpl(); } else if (type == XML_DOCTYPE) { return new XmlDoctypeImpl(); } else if (type == XML_MARKUP_DECL) { return new XmlMarkupDeclImpl(); } else if (type == XML_ELEMENT_DECL) { return new XmlElementDeclImpl(); } else if (type == XML_ENTITY_DECL) { return new XmlEntityDeclImpl(); } else if (type == XML_ATTLIST_DECL) { return new XmlAttlistDeclImpl(); } else if (type == XML_ATTRIBUTE_DECL) { return new XmlAttributeDeclImpl(); } else if (type == XML_NOTATION_DECL) { return new XmlNotationDeclImpl(); } else if (type == XML_ELEMENT_CONTENT_SPEC) { return new XmlElementContentSpecImpl(); } else if (type == XML_ELEMENT_CONTENT_GROUP) { return new XmlElementContentGroupImpl(); } else if (type == XML_ENTITY_REF) { return new XmlEntityRefImpl(); } else if (type == XML_ENUMERATED_TYPE) { return new XmlEnumeratedTypeImpl(); } else if (type == XML_CDATA) { return new CompositePsiElement(XML_CDATA) {}; } else if (type instanceof ITemplateDataElementType) { return new XmlFileElement(type, null); } return null; }
@Override @NotNull public DiffLog reparseRange(@NotNull final PsiFile file, TextRange changedPsiRange, @NotNull final CharSequence newFileText, @NotNull final ProgressIndicator indicator) { final PsiFileImpl fileImpl = (PsiFileImpl)file; Project project = fileImpl.getProject(); final FileElement treeFileElement = fileImpl.getTreeElement(); final CharTable charTable = treeFileElement.getCharTable(); final int textLength = newFileText.length(); int lengthShift = textLength - treeFileElement.getTextLength(); if (treeFileElement.getElementType() instanceof ITemplateDataElementType || isTooDeep(file)) { // unable to perform incremental reparse for template data in JSP, or in exceptionally deep trees return makeFullParse(treeFileElement, newFileText, textLength, fileImpl, indicator); } final ASTNode leafAtStart = treeFileElement.findLeafElementAt(Math.max(0, changedPsiRange.getStartOffset() - 1)); final ASTNode leafAtEnd = treeFileElement.findLeafElementAt(changedPsiRange.getEndOffset()); ASTNode node = leafAtStart != null && leafAtEnd != null ? TreeUtil.findCommonParent(leafAtStart, leafAtEnd) : treeFileElement; Language baseLanguage = file.getViewProvider().getBaseLanguage(); while (node != null && !(node instanceof FileElement)) { IElementType elementType = node.getElementType(); if (elementType instanceof IReparseableElementType) { final TextRange textRange = node.getTextRange(); final IReparseableElementType reparseable = (IReparseableElementType)elementType; if (baseLanguage.isKindOf(reparseable.getLanguage())) { final int start = textRange.getStartOffset(); final int end = start + textRange.getLength() + lengthShift; assertFileLength(file, newFileText, node, elementType, start, end); CharSequence newTextStr = newFileText.subSequence(start, end); if (reparseable.isParsable(newTextStr, baseLanguage, project)) { ASTNode chameleon = reparseable.createNode(newTextStr); if (chameleon != null) { DummyHolder holder = DummyHolderFactory.createHolder(fileImpl.getManager(), null, node.getPsi(), charTable); holder.getTreeElement().rawAddChildren((TreeElement)chameleon); if (holder.getTextLength() != newTextStr.length()) { String details = ApplicationManager.getApplication().isInternal() ? "text=" + newTextStr + "; treeText=" + holder.getText() + ";" : ""; LOG.error("Inconsistent reparse: " + details + " type=" + elementType); } return mergeTrees(fileImpl, node, chameleon, indicator); } } } } node = node.getTreeParent(); } return makeFullParse(node, newFileText, textLength, fileImpl, indicator); }
public CompositeElement createComposite(final IElementType type) { if (type == XML_TAG) { return new XmlTagImpl(); } else if (type == XML_CONDITIONAL_SECTION) { return new XmlConditionalSectionImpl(); } else if (type == HTML_TAG) { return new HtmlTagImpl(); } else if (type == XML_TEXT) { return new XmlTextImpl(); } else if (type == XML_PROCESSING_INSTRUCTION) { return new XmlProcessingInstructionImpl(); } else if (type == XML_DOCUMENT) { return new XmlDocumentImpl(); } else if (type == HTML_DOCUMENT) { return new HtmlDocumentImpl(); } else if (type == XML_PROLOG) { return new XmlPrologImpl(); } else if (type == XML_DECL) { return new XmlDeclImpl(); } else if (type == XML_ATTRIBUTE) { return new XmlAttributeImpl(); } else if (type == XML_ATTRIBUTE_VALUE) { return new XmlAttributeValueImpl(); } else if (type == XML_COMMENT) { return new XmlCommentImpl(); } else if (type == XML_DOCTYPE) { return new XmlDoctypeImpl(); } else if (type == XML_MARKUP_DECL) { return new XmlMarkupDeclImpl(); } else if (type == XML_ELEMENT_DECL) { return new XmlElementDeclImpl(); } else if (type == XML_ENTITY_DECL) { return new XmlEntityDeclImpl(); } else if (type == XML_ATTLIST_DECL) { return new XmlAttlistDeclImpl(); } else if (type == XML_ATTRIBUTE_DECL) { return new XmlAttributeDeclImpl(); } else if (type == XML_NOTATION_DECL) { return new XmlNotationDeclImpl(); } else if (type == XML_ELEMENT_CONTENT_SPEC) { return new XmlElementContentSpecImpl(); } else if (type == XML_ELEMENT_CONTENT_GROUP) { return new XmlElementContentGroupImpl(); } else if (type == XML_ENTITY_REF) { return new XmlEntityRefImpl(); } else if (type == XML_ENUMERATED_TYPE) { return new XmlEnumeratedTypeImpl(); } else if (type == XML_CDATA) { return new CompositePsiElement(XML_CDATA) {}; } else if (type instanceof ITemplateDataElementType) { return new XmlFileElement(type, null); } return null; }
/** * Find ast node that could be reparsed incrementally * * @return Pair (target reparseable node, new replacement node) * or {@code null} if can't parse incrementally. */ @Nullable public static Couple<ASTNode> findReparseableRoots(@Nonnull PsiFileImpl file, @Nonnull FileASTNode oldFileNode, @Nonnull TextRange changedPsiRange, @Nonnull CharSequence newFileText) { Project project = file.getProject(); final FileElement fileElement = (FileElement)oldFileNode; final CharTable charTable = fileElement.getCharTable(); int lengthShift = newFileText.length() - fileElement.getTextLength(); if (fileElement.getElementType() instanceof ITemplateDataElementType || isTooDeep(file)) { // unable to perform incremental reparse for template data in JSP, or in exceptionally deep trees return null; } final ASTNode leafAtStart = fileElement.findLeafElementAt(Math.max(0, changedPsiRange.getStartOffset() - 1)); final ASTNode leafAtEnd = fileElement.findLeafElementAt(Math.min(changedPsiRange.getEndOffset(), fileElement.getTextLength() - 1)); ASTNode node = leafAtStart != null && leafAtEnd != null ? TreeUtil.findCommonParent(leafAtStart, leafAtEnd) : fileElement; Language baseLanguage = file.getViewProvider().getBaseLanguage(); while (node != null && !(node instanceof FileElement)) { IElementType elementType = node.getElementType(); if (elementType instanceof IReparseableElementType) { final TextRange textRange = node.getTextRange(); final IReparseableElementType reparseable = (IReparseableElementType)elementType; if (baseLanguage.isKindOf(reparseable.getLanguage()) && textRange.getLength() + lengthShift > 0) { final int start = textRange.getStartOffset(); final int end = start + textRange.getLength() + lengthShift; if (end > newFileText.length()) { reportInconsistentLength(file, newFileText, node, start, end); break; } CharSequence newTextStr = newFileText.subSequence(start, end); if (reparseable.isParsable(file, newTextStr, baseLanguage, project)) { ASTNode chameleon = reparseable.createNode(newTextStr); if (chameleon != null) { DummyHolder holder = DummyHolderFactory.createHolder(file.getManager(), null, node.getPsi(), charTable); holder.getTreeElement().rawAddChildren((TreeElement)chameleon); if (holder.getTextLength() != newTextStr.length()) { String details = ApplicationManager.getApplication().isInternal() ? "text=" + newTextStr + "; treeText=" + holder.getText() + ";" : ""; LOG.error("Inconsistent reparse: " + details + " type=" + elementType); } return Couple.of(node, chameleon); } } } } node = node.getTreeParent(); } return null; }