@NotNull
  @VisibleForTesting
  public static String suggestTemplateText(@NotNull Editor editor, @Nullable PsiFile file, @NotNull Project project) {
    PsiDocumentManager.getInstance(project).commitAllDocuments();

    TextRange selection = new TextRange(editor.getSelectionModel().getSelectionStart(), editor.getSelectionModel().getSelectionEnd());

    PsiElement[] psiElements = PsiTreeUtil.collectElements(file, element -> selection.contains(element.getTextRange()));

    Document document = EditorFactory.getInstance().createDocument(selection.substring(editor.getDocument().getText()));
    boolean isXml = file != null && file.getLanguage().is(StdLanguages.XML);
    int offsetDelta = editor.getSelectionModel().getSelectionStart();
    WriteCommandAction.writeCommandAction(project).withName(null).run(() -> {
      Map<RangeMarker, String> rangeToText = new HashMap<>();

      for (PsiElement element : psiElements) {
        for (PsiReference reference : element.getReferences()) {
          if (!(reference instanceof PsiQualifiedReference) || ((PsiQualifiedReference)reference).getQualifier() == null) {
            String canonicalText = reference.getCanonicalText();
            TextRange referenceRange = reference.getRangeInElement();
            if (referenceRange.isEmpty()) continue;

            final TextRange elementTextRange = element.getTextRange();
            LOG.assertTrue(elementTextRange != null, elementTextRange);
            final TextRange range = elementTextRange.cutOut(referenceRange).shiftRight(-offsetDelta);
            final String oldText = document.getText(range);
            // workaround for Java references: canonicalText contains generics, and we need to cut them off because otherwise
            // they will be duplicated
            int pos = canonicalText.indexOf('<');
            if (pos > 0 && !oldText.contains("<")) {
              canonicalText = canonicalText.substring(0, pos);
            }
            if (isXml) { //strip namespace prefixes
              pos = canonicalText.lastIndexOf(':');
              if (pos >= 0 && pos < canonicalText.length() - 1 && !oldText.contains(":")) {
                canonicalText = canonicalText.substring(pos + 1);
              }
            }
            if (!canonicalText.equals(oldText)) {
              rangeToText.put(document.createRangeMarker(range), canonicalText);
            }
          }
        }
      }

      List<RangeMarker> markers = new ArrayList<>();
      for (RangeMarker m1 : rangeToText.keySet()) {
        boolean nested = false;
        for (RangeMarker m2 : rangeToText.keySet()) {
          if (m1 != m2 && m2.getStartOffset() <= m1.getStartOffset() && m1.getEndOffset() <= m2.getEndOffset()) {
            nested = true;
            break;
          }
        }

        if (!nested) {
          markers.add(m1);
        }
      }

      for (RangeMarker marker : markers) {
        final String value = rangeToText.get(marker);
        document.replaceString(marker.getStartOffset(), marker.getEndOffset(), value);
      }
    });

    return document.getText().trim();
  }
@NotNull
  @VisibleForTesting
  public static String suggestTemplateText(@NotNull Editor editor, @Nullable PsiFile file, @NotNull Project project)