private static void registerProblem(
      @NotNull final AnnotationHolder holder,
      @NotNull final XmlTag tag,
      @Nullable final XmlToken start,
      @NotNull final XmlToken end) {
    final String tagName = (tag instanceof HtmlTag) ? tag.getName().toLowerCase() : tag.getName();
    final String endTokenText =
        (tag instanceof HtmlTag) ? end.getText().toLowerCase() : end.getText();

    final RenameTagBeginOrEndIntentionAction renameEndAction =
        new RenameTagBeginOrEndIntentionAction(tagName, endTokenText, false);
    final RenameTagBeginOrEndIntentionAction renameStartAction =
        new RenameTagBeginOrEndIntentionAction(endTokenText, tagName, true);

    if (start != null) {
      final Annotation annotation =
          holder.createErrorAnnotation(
              start, XmlErrorMessages.message("tag.has.wrong.closing.tag.name"));
      annotation.registerFix(renameEndAction);
      annotation.registerFix(renameStartAction);
    }

    final Annotation annotation =
        holder.createErrorAnnotation(end, XmlErrorMessages.message("wrong.closing.tag.name"));
    annotation.registerFix(new RemoveExtraClosingTagIntentionAction());
    annotation.registerFix(renameEndAction);
    annotation.registerFix(renameStartAction);
  }
Beispiel #2
0
  /**
   * @param xmlFile
   * @param tagName
   * @param tagValue
   * @param path hierarchy path, this will be the parent of the new tag, ex: root/node1/node2
   * @return
   */
  public static XmlTag createTagInFile(
      final XmlFile xmlFile,
      String tagName,
      String tagValue,
      String path,
      Map<String, String> attributes) {
    XmlTag root = xmlFile.getRootTag();

    String[] pathElements = path.split("/");

    if (pathElements.length > 0 && pathElements[0].equals(root.getName())) {
      XmlTag lastExistentParent = root;
      String curPath = pathElements[0];
      pathElements =
          (String[])
              ArrayUtils.remove(
                  pathElements, 0); // ArrayUtils.removeElement(pathElements, pathElements[0]);
      for (String curTagName : pathElements) {
        lastExistentParent = lastExistentParent.findFirstSubTag(curTagName);
        if (lastExistentParent == null) {
          lastExistentParent = createTagInFile(xmlFile, curTagName, "", curPath);
          if (lastExistentParent == null) {
            return null;
          }
        }
        curPath += "/" + curTagName;
      }
      final XmlTag newTag = lastExistentParent.createChildTag(tagName, "", tagValue, false);

      if (attributes != null) {
        for (Map.Entry<String, String> entry : attributes.entrySet()) {
          newTag.setAttribute(entry.getKey(), entry.getValue());
        }
      }

      final XmlTag parent = lastExistentParent;
      Runnable runnable =
          new Runnable() {
            @Override
            public void run() {
              new WriteCommandAction.Simple(
                  xmlFile.getProject(), "Create Xml Tag in File", xmlFile) {
                @Override
                protected void run() {

                  //                           newTag = (XmlTag)parent.add(newTag);
                  parent.addAfter(newTag, null);
                }
              }.execute();
            }
          };
      runnable.run();
      // PsiDocumentManager.getInstance(xmlFile.getProject()).commitDocument(document);
      return findSubTag(xmlFile, path + "/" + newTag.getName());

    } else {
      return null;
    }
  }
 private static boolean processDevContext(final PsiFile file, Processor<PsiElement> processor) {
   final XmlTag tag = getTagByInjectedFile(file);
   final XmlTag parentTag = tag == null ? null : tag.getParentTag();
   final String parentTagName = parentTag == null ? null : parentTag.getName();
   final String name = tag == null ? null : tag.getName();
   if ("place".equals(name) && "injection".equals(parentTagName)) {
     return processRootsByClassNames(file, parentTag.getAttributeValue("injector-id"), processor);
   } else if ("pattern".equals(name) && parentTag != null) {
     return processRootsByClassNames(file, tag.getAttributeValue("type"), processor);
   }
   return true;
 }
 static boolean checkSchemaNamespace(XmlTag context) {
   final String namespace = context.getNamespace();
   if (namespace.length() > 0) {
     return checkSchemaNamespace(namespace);
   }
   return StringUtil.startsWithConcatenationOf(context.getName(), XSD_PREFIX, ":");
 }
 @Nullable
 private static String getAdditionalDocumentation(PsiElement elem) {
   final XmlTag xmlTag = PsiTreeUtil.getParentOfType(elem, XmlTag.class);
   if (xmlTag == null) {
     return null;
   }
   final AntDomElement antElement = AntSupport.getAntDomElement(xmlTag);
   if (antElement instanceof AntFilesProvider) {
     final List<File> list =
         ((AntFilesProvider) antElement).getFiles(new HashSet<AntFilesProvider>());
     if (list.size() > 0) {
       final @NonNls StringBuilder builder = StringBuilderSpinAllocator.alloc();
       try {
         final XmlTag tag = antElement.getXmlTag();
         if (tag != null) {
           builder.append("<b>");
           builder.append(tag.getName());
           builder.append(":</b>");
         }
         for (File file : list) {
           if (builder.length() > 0) {
             builder.append("<br>");
           }
           builder.append(file.getPath());
         }
         return builder.toString();
       } finally {
         StringBuilderSpinAllocator.dispose(builder);
       }
     }
   }
   return null;
 }
 private void collectPropertiesVariants(final List<Object> result) {
   if (myProjectDom != null) {
     for (XmlTag xmlTag :
         MavenDomProjectProcessorUtils.collectProperties(myProjectDom, myProject)) {
       result.add(createLookupElement(xmlTag, xmlTag.getName(), PlatformIcons.PROPERTY_ICON));
     }
   }
 }
Beispiel #7
0
 /**
  * @param xmlFile
  * @param path absolute Path
  * @return
  */
 public static XmlTag findSubTag(XmlFile xmlFile, String path) {
   XmlTag root = xmlFile.getRootTag();
   if (root != null) {
     String rootName = root.getName();
     String relativePath = path.substring(rootName.length() + 1);
     return findSubTag(root, relativePath);
   }
   return null;
 }
  public void inline(@NotNull XmlTag layoutRootTag) throws AndroidRefactoringErrorException {
    final XmlTag parent = myIncludeTag.getParentTag();

    if ("merge".equals(layoutRootTag.getName()) && parent != null) {
      inlineMultiTags(myIncludeTag, parent, layoutRootTag, myProject);
    } else {
      inlineSingleTag(myIncludeTag, parent, layoutRootTag);
    }
  }
  private void checkTagByDescriptor(final XmlTag tag) {
    String name = tag.getName();

    XmlElementDescriptor elementDescriptor;

    final PsiElement parent = tag.getParent();
    if (parent instanceof XmlTag) {
      XmlTag parentTag = (XmlTag) parent;

      elementDescriptor = XmlUtil.getDescriptorFromContext(tag);

      final XmlElementDescriptor parentDescriptor = parentTag.getDescriptor();

      if (parentDescriptor != null && elementDescriptor == null && shouldBeValidated(tag)) {
        if (tag instanceof HtmlTag) {
          // XmlEntitiesInspection inspection = getInspectionProfile(tag,
          // HtmlStyleLocalInspection.SHORT_NAME);
          // if (inspection != null /*&&
          // isAdditionallyDeclared(inspection.getAdditionalEntries(XmlEntitiesInspection.UNKNOWN_TAG), name)*/) {
          return;
          // }
        }

        addElementsForTag(
            tag,
            XmlErrorMessages.message("element.is.not.allowed.here", name),
            getTagProblemInfoType(tag),
            null);
        return;
      }

      if (elementDescriptor instanceof AnyXmlElementDescriptor || elementDescriptor == null) {
        elementDescriptor = tag.getDescriptor();
      }

      if (elementDescriptor == null) return;
    } else {
      // root tag
      elementDescriptor = tag.getDescriptor();

      if (elementDescriptor == null) {
        addElementsForTag(
            tag,
            XmlErrorMessages.message("element.must.be.declared", name),
            HighlightInfoType.WRONG_REF,
            null);
        return;
      }
    }

    checkRequiredAttributes(tag, name, elementDescriptor);

    if (elementDescriptor instanceof Validator) {
      //noinspection unchecked
      ((Validator<XmlTag>) elementDescriptor).validate(tag, this);
    }
  }
 public boolean isAcceptable(Object element, PsiElement context) {
   for (XmlTag xmlTag : ((XmlTag) element).getSubTags()) {
     if ("filter-class".equals(xmlTag.getName())
         && StripesConstants.STRIPES_FILTER_CLASS.equals(
             xmlTag.getValue().getText())) {
       return true;
     }
   }
   return false;
 }
  HtmlAttributeDescriptor findHtmlAttributeInContext(XmlTag tag) {
    if (tag == null) return null;
    String contextName = tag.getName();

    for (final HtmlAttributeDescriptor attributeDescriptor : attributes) {
      if (attributeDescriptor.isValidParentTagName(contextName)) {
        return attributeDescriptor;
      }
    }

    return null;
  }
  public XmlElementDescriptor getElementDescriptor(XmlTag element, XmlTag contextTag) {
    String name = element.getName();
    if (!myCaseSensitive) name = name.toLowerCase();

    XmlElementDescriptor xmlElementDescriptor = getElementDescriptor(name, element);
    if (xmlElementDescriptor == null && myRelaxed) {
      xmlElementDescriptor =
          RelaxedHtmlFromSchemaElementDescriptor.getRelaxedDescriptor(this, element);
    }

    return xmlElementDescriptor;
  }
 @NotNull
 public XmlTag[] findSubTags(final String name, final String namespace) {
   final XmlTag[] subTags = getSubTags();
   final List<XmlTag> result = new ArrayList<XmlTag>();
   for (final XmlTag subTag : subTags) {
     if (namespace == null) {
       if (name.equals(subTag.getName())) result.add(subTag);
     } else if (name.equals(subTag.getLocalName()) && namespace.equals(subTag.getNamespace())) {
       result.add(subTag);
     }
   }
   return ContainerUtil.toArray(result, new XmlTag[result.size()]);
 }
  @Nullable
  public static XmlTag findProperty(
      @NotNull MavenDomProperties mavenDomProperties, @NotNull String propertyName) {
    XmlTag propertiesTag = mavenDomProperties.getXmlTag();
    if (propertiesTag == null) return null;

    for (XmlTag each : propertiesTag.getSubTags()) {
      if (each.getName().equals(propertyName)) {
        return each;
      }
    }

    return null;
  }
 @Override
 public TextRange getRangeInElement() {
   final TextRange rangeInElement = super.getRangeInElement();
   final XmlTag tagElement = getTagElement();
   if (tagElement != null) {
     final String tagElementName = tagElement.getName();
     final int dotIdx = tagElementName.indexOf(".");
     if (dotIdx > -1 && dotIdx + 2 < rangeInElement.getEndOffset()) {
       return new TextRange(
           rangeInElement.getStartOffset() + dotIdx + 1, rangeInElement.getEndOffset());
     }
   }
   return rangeInElement;
 }
 public void annotate(final PsiElement psiElement, final AnnotationHolder holder) {
   if (psiElement instanceof XmlToken) {
     final PsiElement parent = psiElement.getParent();
     if (parent instanceof XmlTag) {
       final XmlTag tag = (XmlTag) parent;
       final XmlToken start = XmlTagUtil.getStartTagNameElement(tag);
       XmlToken endTagName = XmlTagUtil.getEndTagNameElement(tag);
       if (endTagName != null
           && !(tag instanceof HtmlTag)
           && !tag.getName().equals(endTagName.getText())) {
         registerProblem(holder, tag, start, endTagName);
       } else if (endTagName == null
           && !(tag instanceof HtmlTag && HtmlUtil.isSingleHtmlTag(tag.getName()))) {
         final PsiErrorElement errorElement =
             PsiTreeUtil.getChildOfType(tag, PsiErrorElement.class);
         endTagName = findEndTagName(errorElement);
         if (endTagName != null) {
           registerProblem(holder, tag, start, endTagName);
         }
       }
     } else if (parent instanceof PsiErrorElement) {
       if (XmlTokenType.XML_NAME == ((XmlToken) psiElement).getTokenType()) {
         final PsiFile psiFile = psiElement.getContainingFile();
         if (psiFile != null
             && (HTMLLanguage.INSTANCE == psiFile.getViewProvider().getBaseLanguage()
                 || HTMLLanguage.INSTANCE == parent.getLanguage())) {
           final String message =
               XmlErrorMessages.message("xml.parsing.closing.tag.mathes.nothing");
           if (message.equals(((PsiErrorElement) parent).getErrorDescription())) {
             final Annotation annotation = holder.createWarningAnnotation(parent, message);
             annotation.registerFix(new RemoveExtraClosingTagIntentionAction());
           }
         }
       }
     }
   }
 }
 @Override
 public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
   if (element instanceof PsiClass) {
     final String qualifiedName = ((PsiClass) element).getQualifiedName();
     if (qualifiedName != null) {
       final String shortName = StringUtil.getShortName(qualifiedName);
       final XmlTag tagElement = getTagElement();
       if (tagElement != null) {
         final String oldTagName = tagElement.getName();
         if (oldTagName.contains(".")) {
           return tagElement.setName(qualifiedName);
         }
         return tagElement.setName(shortName);
       }
       return getElement();
     }
   }
   return super.bindToElement(element);
 }
 private Map<String, XmlElementDescriptor> configure(String... files) {
   myFixture.configureByFiles(files);
   XmlTag tag = ((XmlFile) getFile()).getRootTag();
   assertNotNull(tag);
   XmlElementDescriptor descriptor = tag.getDescriptor();
   assertNotNull(descriptor);
   XmlElementDescriptor[] descriptors = descriptor.getElementsDescriptors(tag);
   Map<String, XmlElementDescriptor> map =
       ContainerUtil.assignKeys(
           Arrays.asList(descriptors).iterator(),
           new Convertor<XmlElementDescriptor, String>() {
             @Override
             public String convert(XmlElementDescriptor o) {
               return o.getName();
             }
           });
   map.put(tag.getName(), tag.getDescriptor());
   return map;
 }
  @Nullable
  private static VirtualFile getHelpFile(
      AntDomElement antElement, final VirtualFile documentationRoot) {
    final XmlTag xmlTag = antElement.getXmlTag();
    if (xmlTag == null) {
      return null;
    }
    @NonNls final String helpFileShortName = "/" + xmlTag.getName() + ".html";

    VirtualFile candidateHelpFile =
        documentationRoot.findFileByRelativePath(CORE_TASKS_FOLDER_NAME + helpFileShortName);
    if (candidateHelpFile != null) {
      return candidateHelpFile;
    }

    candidateHelpFile =
        documentationRoot.findFileByRelativePath(OPTIONAL_TASKS_FOLDER_NAME + helpFileShortName);
    if (candidateHelpFile != null) {
      return candidateHelpFile;
    }

    candidateHelpFile =
        documentationRoot.findFileByRelativePath(CORE_TYPES_FOLDER_NAME + helpFileShortName);
    if (candidateHelpFile != null) {
      return candidateHelpFile;
    }

    candidateHelpFile =
        documentationRoot.findFileByRelativePath(OPTIONAL_TYPES_FOLDER_NAME + helpFileShortName);
    if (candidateHelpFile != null) {
      return candidateHelpFile;
    }

    if (antElement instanceof AntDomTarget || antElement instanceof AntDomProject) {
      candidateHelpFile = documentationRoot.findFileByRelativePath("using.html");
      if (candidateHelpFile != null) {
        return candidateHelpFile;
      }
    }

    return null;
  }
  public static boolean isSettingsFile(PsiFile file) {
    if (!(file instanceof XmlFile)) return false;

    XmlTag rootTag = ((XmlFile) file).getRootTag();
    if (rootTag == null || !"settings".equals(rootTag.getName())) return false;

    String xmlns = rootTag.getAttributeValue("xmlns");
    if (xmlns != null) {
      return xmlns.contains("maven");
    }

    boolean hasTag = false;

    for (PsiElement e = rootTag.getFirstChild(); e != null; e = e.getNextSibling()) {
      if (e instanceof XmlTag) {
        if (SUBTAGS_IN_SETTINGS_FILE.contains(((XmlTag) e).getName())) return true;
        hasTag = true;
      }
    }

    return !hasTag;
  }
Beispiel #21
0
  @Nullable
  public String getInstalledPluginNameByPath(Project project, @NotNull VirtualFile pluginPath) {
    VirtualFile pluginXml = pluginPath.findChild("plugin.xml");
    if (pluginXml == null) return null;

    PsiFile pluginXmlPsi = PsiManager.getInstance(project).findFile(pluginXml);
    if (!(pluginXmlPsi instanceof XmlFile)) return null;

    XmlTag rootTag = ((XmlFile) pluginXmlPsi).getRootTag();
    if (rootTag == null || !"plugin".equals(rootTag.getName())) return null;

    XmlAttribute attrName = rootTag.getAttribute("name");
    if (attrName == null) return null;

    String res = attrName.getValue();
    if (res == null) return null;

    res = res.trim();
    if (res.length() == 0) return null;

    return res;
  }
  private PsiElement tryResolveToActivationSection() {
    XmlTag xmlTag = PsiTreeUtil.getParentOfType(getElement(), XmlTag.class);
    while (xmlTag != null) {
      if (xmlTag.getName().equals("profile")) {
        XmlTag activation = xmlTag.findFirstSubTag("activation");
        if (activation != null) {
          for (XmlTag propertyTag : activation.findSubTags("property")) {
            XmlTag nameTag = propertyTag.findFirstSubTag("name");
            if (nameTag != null) {
              if (nameTag.getValue().getTrimmedText().equals(myText)) {
                return nameTag;
              }
            }
          }
        }
        break;
      }

      xmlTag = xmlTag.getParentTag();
    }

    return null;
  }
  @Nullable
  public static XmlTag findTag(@NotNull DomElement domElement, @NotNull String path) {
    List<String> elements = StringUtil.split(path, ".");
    if (elements.isEmpty()) return null;

    Pair<String, Integer> nameAndIndex = translateTagName(elements.get(0));
    String name = nameAndIndex.first;
    Integer index = nameAndIndex.second;

    XmlTag result = domElement.getXmlTag();
    if (result == null || !name.equals(result.getName())) return null;
    result = getIndexedTag(result, index);

    for (String each : elements.subList(1, elements.size())) {
      nameAndIndex = translateTagName(each);
      name = nameAndIndex.first;
      index = nameAndIndex.second;

      result = result.findFirstSubTag(name);
      if (result == null) return null;
      result = getIndexedTag(result, index);
    }
    return result;
  }
  @Override
  protected void checkTag(
      @NotNull final XmlTag tag, @NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
    if (!(tag instanceof HtmlTag)
        || !XmlHighlightVisitor.shouldBeValidated(tag)
        || isInSpecialHtml5Namespace(tag)) {
      return;
    }

    XmlElementDescriptor descriptorFromContext = XmlUtil.getDescriptorFromContext(tag);

    PsiElement parent = tag.getParent();
    XmlElementDescriptor parentDescriptor =
        parent instanceof XmlTag ? ((XmlTag) parent).getDescriptor() : null;

    XmlElementDescriptor ownDescriptor =
        isAbstractDescriptor(descriptorFromContext) ? tag.getDescriptor() : descriptorFromContext;

    if (isAbstractDescriptor(ownDescriptor)
        || (parentDescriptor instanceof HtmlElementDescriptorImpl
            && ownDescriptor instanceof HtmlElementDescriptorImpl
            && isAbstractDescriptor(descriptorFromContext))) {

      final String name = tag.getName();

      if (!isCustomValuesEnabled() || !isCustomValue(name)) {
        final AddCustomTagOrAttributeIntentionAction action =
            new AddCustomTagOrAttributeIntentionAction(
                TAG_KEY, name, XmlEntitiesInspection.UNKNOWN_TAG);

        // todo: support "element is not allowed" message for html5
        // some tags in html5 cannot be found in xhtml5.xsd if they are located in incorrect
        // context, so they get any-element descriptor (ex. "canvas: tag)
        final String message =
            isAbstractDescriptor(ownDescriptor)
                ? XmlErrorMessages.message("unknown.html.tag", name)
                : XmlErrorMessages.message("element.is.not.allowed.here", name);

        final PsiElement startTagName = XmlTagUtil.getStartTagNameElement(tag);
        assert startTagName != null;
        final PsiElement endTagName = XmlTagUtil.getEndTagNameElement(tag);

        List<LocalQuickFix> quickfixes = new ArrayList<LocalQuickFix>();
        quickfixes.add(action);
        if (isOnTheFly) {
          ContainerUtil.addIfNotNull(
              CreateNSDeclarationIntentionFix.createFix(startTagName, ""), quickfixes);
        }
        if (HtmlUtil.isHtml5Tag(name) && !HtmlUtil.hasNonHtml5Doctype(tag)) {
          quickfixes.add(new SwitchToHtml5WithHighPriorityAction());
        }
        ProblemHighlightType highlightType =
            tag.getContainingFile().getContext() == null
                ? ProblemHighlightType.GENERIC_ERROR_OR_WARNING
                : ProblemHighlightType.INFORMATION;
        if (startTagName.getTextLength() > 0) {
          holder.registerProblem(
              startTagName,
              message,
              highlightType,
              quickfixes.toArray(new LocalQuickFix[quickfixes.size()]));
        }

        if (endTagName != null) {
          holder.registerProblem(
              endTagName,
              message,
              highlightType,
              quickfixes.toArray(new LocalQuickFix[quickfixes.size()]));
        }
      }
    }
  }
  public Result beforeCharTyped(
      final char c,
      final Project project,
      final Editor editor,
      final PsiFile editedFile,
      final FileType fileType) {
    final XmlEditorOptions xmlEditorOptions = XmlEditorOptions.getInstance();
    if (c == '>'
        && xmlEditorOptions != null
        && xmlEditorOptions.isAutomaticallyInsertClosingTag()
        && (editedFile.getLanguage() instanceof XMLLanguage
            || editedFile.getViewProvider().getBaseLanguage() instanceof XMLLanguage)) {
      PsiDocumentManager.getInstance(project).commitAllDocuments();

      PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
      FileViewProvider provider = editedFile.getViewProvider();
      int offset = editor.getCaretModel().getOffset();

      PsiElement element, elementAtCaret = null;

      if (offset < editor.getDocument().getTextLength()) {
        elementAtCaret = element = provider.findElementAt(offset, XMLLanguage.class);

        if (!(element instanceof PsiWhiteSpace)) {
          boolean nonAcceptableDelimiter = true;

          if (element instanceof XmlToken) {
            IElementType tokenType = ((XmlToken) element).getTokenType();

            if (tokenType == XmlTokenType.XML_START_TAG_START
                || tokenType == XmlTokenType.XML_END_TAG_START) {
              if (offset > 0) {
                PsiElement previousElement = provider.findElementAt(offset - 1, XMLLanguage.class);

                if (previousElement instanceof XmlToken) {
                  tokenType = ((XmlToken) previousElement).getTokenType();
                  element = previousElement;
                  nonAcceptableDelimiter = false;
                }
              }
            } else if (tokenType == XmlTokenType.XML_NAME) {
              if (element.getNextSibling() instanceof PsiErrorElement) {
                nonAcceptableDelimiter = false;
              }
            }

            if (tokenType == XmlTokenType.XML_TAG_END
                || tokenType == XmlTokenType.XML_EMPTY_ELEMENT_END
                    && element.getTextOffset() == offset - 1) {
              editor.getCaretModel().moveToOffset(offset + 1);
              editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
              return Result.STOP;
            }
          }
          if (nonAcceptableDelimiter) return Result.CONTINUE;
        } else {
          // check if right after empty end
          PsiElement previousElement = provider.findElementAt(offset - 1, XMLLanguage.class);
          if (previousElement instanceof XmlToken) {
            final IElementType tokenType = ((XmlToken) previousElement).getTokenType();

            if (tokenType == XmlTokenType.XML_EMPTY_ELEMENT_END) {
              return Result.STOP;
            }
          }
        }

        PsiElement parent = element.getParent();
        if (parent instanceof XmlText) {
          final String text = parent.getText();
          // check /
          final int index = offset - parent.getTextOffset() - 1;

          if (index >= 0 && text.charAt(index) == '/') {
            return Result.CONTINUE; // already seen /
          }
          element = parent.getPrevSibling();
        } else if (parent instanceof XmlTag && !(element.getPrevSibling() instanceof XmlTag)) {
          element = parent;
        } else if (parent instanceof XmlAttributeValue) {
          element = parent;
        }
      } else {
        element =
            provider.findElementAt(editor.getDocument().getTextLength() - 1, XMLLanguage.class);
        if (element == null) return Result.CONTINUE;
        element = element.getParent();
      }

      if (offset > 0 && offset <= editor.getDocument().getTextLength()) {
        if (editor.getDocument().getCharsSequence().charAt(offset - 1)
            == '/') { // Some languages (e.g. GSP) allow character '/' in tag name.
          return Result.CONTINUE;
        }
      }

      if (element instanceof XmlAttributeValue) {
        element = element.getParent().getParent();
      }

      while (element instanceof PsiWhiteSpace) element = element.getPrevSibling();
      if (element instanceof XmlDocument) { // hack for closing tags in RHTML
        element = element.getLastChild();
      }
      if (element == null) return Result.CONTINUE;
      if (!(element instanceof XmlTag)) {
        if (element instanceof XmlTokenImpl
            && element.getPrevSibling() != null
            && element.getPrevSibling().getText().equals("<")) {
          // tag is started and there is another text in the end
          editor.getDocument().insertString(offset, "</" + element.getText() + ">");
        }
        return Result.CONTINUE;
      }

      XmlTag tag = (XmlTag) element;
      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;
      final XmlToken startToken = XmlUtil.getTokenOfType(tag, XmlTokenType.XML_START_TAG_START);
      if (startToken == null || !startToken.getText().equals("<")) return Result.CONTINUE;

      String name = tag.getName();
      if (elementAtCaret instanceof XmlToken
          && ((XmlToken) elementAtCaret).getTokenType() == XmlTokenType.XML_NAME) {
        name = name.substring(0, offset - elementAtCaret.getTextOffset());
      }
      if (tag instanceof HtmlTag && HtmlUtil.isSingleHtmlTag(name)) return Result.CONTINUE;
      if ("".equals(name)) return Result.CONTINUE;

      int tagOffset = tag.getTextRange().getStartOffset();

      final XmlToken nameToken = XmlUtil.getTokenOfType(tag, XmlTokenType.XML_NAME);
      if (nameToken != null && nameToken.getTextRange().getStartOffset() > offset)
        return Result.CONTINUE;

      HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(tagOffset);
      if (BraceMatchingUtil.matchBrace(
          editor.getDocument().getCharsSequence(),
          editedFile.getFileType(),
          iterator,
          true,
          true)) {
        PsiElement parent = tag.getParent();
        boolean hasBalance = true;

        while (parent instanceof XmlTag && name.equals(((XmlTag) parent).getName())) {
          ASTNode astNode = XmlChildRole.CLOSING_TAG_NAME_FINDER.findChild(parent.getNode());
          if (astNode == null) {
            hasBalance = false;
            break;
          }

          parent = parent.getParent();
        }

        if (hasBalance) {
          hasBalance = false;
          for (ASTNode node = parent.getNode().getLastChildNode();
              node != null;
              node = node.getTreePrev()) {
            ASTNode leaf = node;
            if (leaf.getElementType() == TokenType.ERROR_ELEMENT) {
              ASTNode firstChild = leaf.getFirstChildNode();
              if (firstChild != null) leaf = firstChild;
              else {
                PsiElement psiElement = PsiTreeUtil.nextLeaf(leaf.getPsi());
                leaf = psiElement != null ? psiElement.getNode() : null;
              }
              if (leaf != null && leaf.getElementType() == TokenType.WHITE_SPACE) {
                PsiElement psiElement = PsiTreeUtil.nextLeaf(leaf.getPsi());
                if (psiElement != null) leaf = psiElement.getNode();
              }
            }

            if (leaf != null && leaf.getElementType() == XmlTokenType.XML_END_TAG_START) {
              ASTNode treeNext = leaf.getTreeNext();
              IElementType treeNextType;
              if (treeNext != null
                  && ((treeNextType = treeNext.getElementType()) == XmlTokenType.XML_NAME
                      || treeNextType == XmlTokenType.XML_TAG_NAME)) {
                if (name.equals(treeNext.getText())) {
                  ASTNode parentEndName =
                      parent instanceof XmlTag
                          ? XmlChildRole.CLOSING_TAG_NAME_FINDER.findChild(parent.getNode())
                          : null;
                  hasBalance =
                      !(parent instanceof XmlTag)
                          || parentEndName != null && !parentEndName.getText().equals(name);
                  break;
                }
              }
            }
          }
        }

        if (hasBalance) return Result.CONTINUE;
      }

      TextRange cdataReformatRange = null;
      final XmlElementDescriptor descriptor = tag.getDescriptor();

      if (descriptor instanceof XmlElementDescriptorWithCDataContent) {
        final XmlElementDescriptorWithCDataContent cDataContainer =
            (XmlElementDescriptorWithCDataContent) descriptor;

        if (cDataContainer.requiresCdataBracesInContext(tag)) {
          int rangeStart = offset;
          @NonNls final String cDataStart = "><![CDATA[";
          final String inserted = cDataStart + "\n]]>";
          editor.getDocument().insertString(offset, inserted);
          final int newoffset = offset + cDataStart.length();
          editor.getCaretModel().moveToOffset(newoffset);
          offset += inserted.length();
          cdataReformatRange = new TextRange(rangeStart, offset + 1);
        }
      }

      editor.getDocument().insertString(offset, "</" + name + ">");

      if (cdataReformatRange != null) {
        PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
        try {
          CodeStyleManager.getInstance(project)
              .reformatText(
                  file, cdataReformatRange.getStartOffset(), cdataReformatRange.getEndOffset());
        } catch (IncorrectOperationException e) {
          LOG.error(e);
        }
      }
      return cdataReformatRange != null ? Result.STOP : Result.CONTINUE;
    }
    return Result.CONTINUE;
  }
 private static boolean isNameSuitable(
     final EvaluatedXmlName evaluatedXmlName, final XmlTag tag, final XmlFile file) {
   return isNameSuitable(
       evaluatedXmlName, tag.getLocalName(), tag.getName(), tag.getNamespace(), file);
 }
 static AbstractDomChildrenDescription findChildrenDescription(
     final XmlTag tag, final DomInvocationHandler parent) {
   final DomGenericInfoEx info = parent.getGenericInfo();
   return info.findChildrenDescription(
       parent, tag.getLocalName(), tag.getNamespace(), false, tag.getName());
 }