private boolean extractFrom(final @NotNull PsiElement start, final PsiElement end, String newName) {
        final XmlTag outerTemplate = XsltCodeInsightUtil.getTemplateTag(start, false);
        if (outerTemplate == null) {
            return false;
        }
        final XmlTag parentScope = PsiTreeUtil.getParentOfType(start, XmlTag.class, true);
        if (parentScope == null) {
          return false;
        }

        final StringBuilder sb = new StringBuilder("\n");
        final Set<String> vars = new LinkedHashSet<>();

        final int startOffset = start.getTextRange().getStartOffset();
        final int endOffset = end.getTextRange().getEndOffset();

        PsiElement e = start;
        while (e != null) {
            if (e instanceof XmlTag tag) {
              if (XsltSupport.isVariable(tag)) {
                    final XsltVariable variable = XsltElementFactory.getInstance().wrapElement(tag, XsltVariable.class);
                    final LocalSearchScope searchScope = new LocalSearchScope(parentScope);
                    final Query<PsiReference> query = ReferencesSearch.search(variable, searchScope);
                    for (PsiReference reference : query) {
                        final XmlElement context = PsiTreeUtil.getContextOfType(reference.getElement(), XmlElement.class, true);
                        if (context == null || context.getTextRange().getStartOffset() > endOffset) {
                            return false;
                        }
                    }
                }
            }
            sb.append(e.getText());

            final List<XPathVariableReference> references = RefactoringUtil.collectVariableReferences(e);
            for (XPathVariableReference reference : references) {
                final XPathVariable variable = reference.resolve();
                if (variable instanceof XsltVariable) {
                    final XmlTag var = ((XsltVariable)variable).getTag();
                    if (var.getTextRange().getStartOffset() < startOffset) {
                        // don't pass through global parameters and variables
                        if (XsltCodeInsightUtil.getTemplateTag(variable, false) != null) {
                            vars.add(variable.getName());
                        }
                    }
                } else if (variable == null) {
                    // TODO just copy unresolved refs or fail?
                    vars.add(reference.getReferencedName());
                }
            }

            if (e == end) {
                break;
            }
            e = e.getNextSibling();
        }
        sb.append("\n");

        final String s = newName == null ?
                Messages.showInputDialog(start.getProject(), XPathBundle.message("dialog.message.template.name"), getRefactoringName(), Messages.getQuestionIcon()) :
                newName;

        if (s != null) {
            WriteCommandAction.runWriteCommandAction(start.getProject(), ()-> {
                final PsiFile containingFile = start.getContainingFile();

                XmlTag templateTag = parentScope.createChildTag("template", XsltSupport.XSLT_NS, sb.toString(), false);
                templateTag.setAttribute("name", s);

                final PsiElement dummy = XmlElementFactory.getInstance(start.getProject()).createDisplayText(" ");
                final PsiElement outerParent = outerTemplate.getParent();
                final PsiElement element = outerParent.addAfter(dummy, outerTemplate);
                templateTag = (XmlTag)outerParent.addAfter(templateTag, element);

                final TextRange adjust = templateTag.getTextRange();

                final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(start.getProject());
                final Document doc = psiDocumentManager.getDocument(containingFile);
                assert doc != null;
                psiDocumentManager.doPostponedOperationsAndUnblockDocument(doc);
                CodeStyleManager.getInstance(start.getManager().getProject()).adjustLineIndent(containingFile, adjust);

                final PsiElement parent = start.getParent();
                XmlTag callTag = parentScope.createChildTag("call-template", XsltSupport.XSLT_NS, null, false);
                callTag.setAttribute("name", s);

                if (start instanceof XmlToken && ((XmlToken)start).getTokenType() == XmlTokenType.XML_DATA_CHARACTERS) {
                    assert start == end;
                    callTag = (XmlTag)start.replace(callTag);
                } else {
                    callTag = (XmlTag)parent.addBefore(callTag, start);
                    parent.deleteChildRange(start, end);
                }

                for (String var : vars) {
                    final XmlTag param = templateTag.createChildTag("param", XsltSupport.XSLT_NS, null, false);
                    param.setAttribute("name", var);
                    RefactoringUtil.addParameter(templateTag, param);

                    final XmlTag arg = RefactoringUtil.addWithParam(callTag);
                    arg.setAttribute("name", var);
                    arg.setAttribute("select", "$" + var);
                }
            });
        }
        return true;
    }
private boolean extractFrom(final @NotNull PsiElement start, final PsiElement end, String newName)