Result (final char c, final @NotNull Project project, final @NotNull Editor editor, final @NotNull PsiFile editedFile) { if (!WebEditorOptions.getInstance().isAutoCloseTag()) return Result.CONTINUE; if (c == '/' && XmlGtTypedHandler.fileContainsXmlLanguage(editedFile)) { PsiDocumentManager.getInstance(project).commitAllDocuments(); PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); if (file == null) return Result.CONTINUE; FileViewProvider provider = file.getViewProvider(); final int offset = editor.getCaretModel().getOffset(); PsiElement element = provider.findElementAt(offset - 1, XMLLanguage.class); if (element == null) return Result.CONTINUE; if (!(element.getLanguage() instanceof XMLLanguage)) return Result.CONTINUE; ASTNode prevLeaf = element.getNode(); if (prevLeaf == null) return Result.CONTINUE; final String prevLeafText = prevLeaf.getText(); if ("</".equals(prevLeafText) && prevLeaf.getElementType() == XmlTokenType.XML_END_TAG_START) { XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class); if (tag != null && StringUtil.isNotEmpty(tag.getName()) && TreeUtil.findSibling(prevLeaf, XmlTokenType.XML_NAME) == null && TreeUtil.findSibling(prevLeaf, XmlTokenType.XML_TAG_NAME) == null) { // check for template language like JSP if (provider instanceof MultiplePsiFilesPerDocumentFileViewProvider) { PsiElement element1 = AbstractFileViewProvider.findElementAt(file, offset - 1); if (element1 != null) { // case of top-level jsp tag XmlTag tag1 = PsiTreeUtil.getParentOfType(element1, XmlTag.class); if (shouldReplace(tag, tag1, offset)) { tag = tag1; } else { // if we have enclosing jsp tag, actual tag to be completed will be previous sibling tag1 = PsiTreeUtil.getPrevSiblingOfType(element1.getParent(), XmlTag.class); if (shouldReplace(tag, tag1, offset)) { tag = tag1; } } } } EditorModificationUtil.insertStringAtCaret(editor, tag.getName() + ">", false); autoIndent(editor); return Result.STOP; } } if (!"/".equals(prevLeafText.trim())) return Result.CONTINUE; while ((prevLeaf = TreeUtil.prevLeaf(prevLeaf)) != null && prevLeaf.getElementType() == XmlTokenType.XML_WHITE_SPACE) ; if (prevLeaf instanceof OuterLanguageElement) { element = file.getViewProvider().findElementAt(offset - 1, file.getLanguage()); prevLeaf = element != null ? element.getNode() : null; while ((prevLeaf = TreeUtil.prevLeaf(prevLeaf)) != null && prevLeaf.getElementType() == XmlTokenType.XML_WHITE_SPACE) ; } if (prevLeaf == null) return Result.CONTINUE; XmlTag tag = PsiTreeUtil.getParentOfType(prevLeaf.getPsi(), XmlTag.class); if (tag == null) { // prevLeaf maybe in one tree and element in another PsiElement element2 = provider.findElementAt(prevLeaf.getStartOffset(), XMLLanguage.class); tag = PsiTreeUtil.getParentOfType(element2, XmlTag.class); if (tag == null) return Result.CONTINUE; } final XmlToken startToken = XmlUtil.getTokenOfType(tag, XmlTokenType.XML_START_TAG_START); if (startToken == null || !startToken.getText().equals("<")) return Result.CONTINUE; if (XmlUtil.getTokenOfType(tag, XmlTokenType.XML_TAG_END) != null) return Result.CONTINUE; if (XmlUtil.getTokenOfType(tag, XmlTokenType.XML_EMPTY_ELEMENT_END) != null) return Result.CONTINUE; if (PsiTreeUtil.getParentOfType(element, XmlAttributeValue.class) != null) return Result.CONTINUE; EditorModificationUtil.insertStringAtCaret(editor, ">", false); return Result.STOP; } return Result.CONTINUE; }