private static Collection<String> suggestKeywords(PsiElement position) {
    TextRange posRange = position.getTextRange();
    BnfFile posFile = (BnfFile) position.getContainingFile();
    BnfRule statement = PsiTreeUtil.getTopmostParentOfType(position, BnfRule.class);
    final TextRange range;
    if (statement != null) {
      range = new TextRange(statement.getTextRange().getStartOffset(), posRange.getStartOffset());
    } else {
      int offset = posRange.getStartOffset();
      for (PsiElement cur = GrammarUtil.getDummyAwarePrevSibling(position);
          cur != null;
          cur = GrammarUtil.getDummyAwarePrevSibling(cur)) {
        if (cur instanceof BnfAttrs) offset = cur.getTextRange().getEndOffset();
        else if (cur instanceof BnfRule) offset = cur.getTextRange().getStartOffset();
        else continue;
        break;
      }
      range = new TextRange(offset, posRange.getStartOffset());
    }
    final String text =
        range.isEmpty()
            ? CompletionInitializationContext.DUMMY_IDENTIFIER
            : range.substring(posFile.getText());

    PsiFile file =
        PsiFileFactory.getInstance(posFile.getProject())
            .createFileFromText("a.bnf", BnfLanguage.INSTANCE, text, true, false);
    int completionOffset = posRange.getStartOffset() - range.getStartOffset();
    GeneratedParserUtilBase.CompletionState state =
        new GeneratedParserUtilBase.CompletionState(completionOffset) {
          @Override
          public String convertItem(Object o) {
            // we do not have other keywords
            return o instanceof String ? (String) o : null;
          }
        };
    file.putUserData(GeneratedParserUtilBase.COMPLETION_STATE_KEY, state);
    TreeUtil.ensureParsed(file.getNode());
    return state.items;
  }
  @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();
  }