@Override
  public void inlineElement(Project project, Editor editor, PsiElement psiElement) {
    BnfRule rule = (BnfRule) psiElement;
    BnfAttrs attrs = rule.getAttrs();
    if (PsiTreeUtil.hasErrorElements(rule)) {
      CommonRefactoringUtil.showErrorHint(project, editor, "Rule has errors", "Inline Rule", null);
      return;
    }

    if (attrs != null && !attrs.getAttrList().isEmpty()) {
      CommonRefactoringUtil.showErrorHint(
          project, editor, "Rule has attributes", "Inline Rule", null);
      return;
    }

    Collection<PsiReference> allReferences = ReferencesSearch.search(psiElement).findAll();
    if (allReferences.isEmpty()) {
      CommonRefactoringUtil.showErrorHint(
          project, editor, "Rule is never used", "Inline Rule", null);
      return;
    }

    boolean hasNonAttributeRefs = false;
    for (PsiReference ref : allReferences) {
      if (!GrammarUtil.isInAttributesReference(ref.getElement())) {
        hasNonAttributeRefs = true;
        break;
      }
    }
    if (!hasNonAttributeRefs) {
      CommonRefactoringUtil.showErrorHint(
          project, editor, "Rule is referenced only in attributes", "Inline Rule", null);
      return;
    }
    if (!CommonRefactoringUtil.checkReadOnlyStatus(project, rule)) return;
    PsiReference reference =
        editor != null
            ? TargetElementUtilBase.findReference(editor, editor.getCaretModel().getOffset())
            : null;
    if (reference != null && !rule.equals(reference.resolve())) {
      reference = null;
    }

    InlineRuleDialog dialog = new InlineRuleDialog(project, rule, reference);
    dialog.show();
  }
  @NotNull
  @Override
  public FoldingDescriptor[] buildFoldRegions(
      @NotNull PsiElement root, @NotNull Document document, boolean quick) {
    if (!(root instanceof BnfFile)) return FoldingDescriptor.EMPTY;
    BnfFile file = (BnfFile) root;

    final ArrayList<FoldingDescriptor> result = new ArrayList<FoldingDescriptor>();
    for (BnfAttrs attrs : file.getAttributes()) {
      TextRange textRange = attrs.getTextRange();
      if (textRange.getLength() <= 2) continue;
      result.add(new FoldingDescriptor(attrs, textRange));
    }
    for (BnfRule rule : file.getRules()) {
      // result.add(new FoldingDescriptor(rule, rule.getTextRange()));
      BnfAttrs attrs = rule.getAttrs();
      if (attrs != null) {
        result.add(new FoldingDescriptor(attrs, attrs.getTextRange()));
      }
    }
    if (!quick) {
      PsiTreeUtil.processElements(
          file,
          new PsiElementProcessor() {
            @Override
            public boolean execute(@NotNull PsiElement element) {
              if (element.getNode().getElementType() == BnfParserDefinition.BNF_BLOCK_COMMENT) {
                result.add(new FoldingDescriptor(element, element.getTextRange()));
              }
              return true;
            }
          });
    }

    return result.toArray(new FoldingDescriptor[result.size()]);
  }