public boolean analyze(
     @NotNull final PsiFile file,
     final boolean updateWholeFile,
     @NotNull HighlightInfoHolder holder,
     @NotNull Runnable action) {
   myHolder = holder;
   try {
     action.run();
   } finally {
     myHolder = null;
   }
   return true;
 }
  @Override
  public void invoke(
      @NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile file) {
    if (!CodeInsightUtilBase.prepareEditorForWrite(editor)) return;
    try {
      final XmlTag contextTag = getContextTag(editor, file);
      if (contextTag == null) {
        throw new CommonRefactoringUtil.RefactoringErrorHintException(
            "Caret should be positioned inside a tag");
      }
      XmlElementDescriptor currentTagDescriptor = contextTag.getDescriptor();
      assert currentTagDescriptor != null;
      final XmlElementDescriptor[] descriptors =
          currentTagDescriptor.getElementsDescriptors(contextTag);
      Arrays.sort(
          descriptors,
          new Comparator<XmlElementDescriptor>() {
            @Override
            public int compare(XmlElementDescriptor o1, XmlElementDescriptor o2) {
              return o1.getName().compareTo(o2.getName());
            }
          });
      final JBList list = new JBList(descriptors);
      list.setCellRenderer(new MyListCellRenderer());
      Runnable runnable =
          new Runnable() {
            @Override
            public void run() {
              final XmlElementDescriptor selected = (XmlElementDescriptor) list.getSelectedValue();
              new WriteCommandAction.Simple(project, "Generate XML Tag", file) {
                @Override
                protected void run() {
                  if (selected == null) return;
                  XmlTag newTag = createTag(contextTag, selected);

                  PsiElement anchor = getAnchor(contextTag, editor, selected);
                  if (anchor == null) { // insert it in the cursor position
                    int offset = editor.getCaretModel().getOffset();
                    Document document = editor.getDocument();
                    document.insertString(offset, newTag.getText());
                    PsiDocumentManager.getInstance(project).commitDocument(document);
                    newTag =
                        PsiTreeUtil.getParentOfType(
                            file.findElementAt(offset + 1), XmlTag.class, false);
                  } else {
                    newTag = (XmlTag) contextTag.addAfter(newTag, anchor);
                  }
                  if (newTag != null) {
                    generateTag(newTag, editor);
                  }
                }
              }.execute();
            }
          };
      if (ApplicationManager.getApplication().isUnitTestMode()) {
        XmlElementDescriptor descriptor =
            ContainerUtil.find(
                descriptors,
                new Condition<XmlElementDescriptor>() {
                  @Override
                  public boolean value(XmlElementDescriptor xmlElementDescriptor) {
                    return xmlElementDescriptor.getName().equals(TEST_THREAD_LOCAL.get());
                  }
                });
        list.setSelectedValue(descriptor, false);
        runnable.run();
      } else {
        JBPopupFactory.getInstance()
            .createListPopupBuilder(list)
            .setTitle("Choose Tag Name")
            .setItemChoosenCallback(runnable)
            .setFilteringEnabled(
                new Function<Object, String>() {
                  @Override
                  public String fun(Object o) {
                    return ((XmlElementDescriptor) o).getName();
                  }
                })
            .createPopup()
            .showInBestPositionFor(editor);
      }
    } catch (CommonRefactoringUtil.RefactoringErrorHintException e) {
      HintManager.getInstance().showErrorHint(editor, e.getMessage());
    }
  }