public static List<CustomLiveTemplate> listApplicableCustomTemplates(
     @NotNull Editor editor, @NotNull PsiFile file, boolean selectionOnly) {
   List<CustomLiveTemplate> result = new ArrayList<CustomLiveTemplate>();
   for (CustomLiveTemplate template : CustomLiveTemplate.EP_NAME.getExtensions()) {
     if ((!selectionOnly || template.supportsWrapping())
         && isApplicable(template, editor, file, selectionOnly)) {
       result.add(template);
     }
   }
   return result;
 }
 @NotNull
 public static String findLiveTemplatePrefix(
     @NotNull PsiFile file, @NotNull Editor editor, @NotNull String defaultValue) {
   final CustomTemplateCallback callback = new CustomTemplateCallback(editor, file, false);
   for (CustomLiveTemplate customLiveTemplate : CustomLiveTemplate.EP_NAME.getExtensions()) {
     final String customKey = customLiveTemplate.computeTemplateKey(callback);
     if (customKey != null) {
       return customKey;
     }
   }
   return defaultValue;
 }
  @Nullable
  public Runnable prepareTemplate(
      final Editor editor,
      char shortcutChar,
      @Nullable final PairProcessor<String, String> processor) {
    if (editor.getSelectionModel().hasSelection()) {
      return null;
    }

    PsiFile file = PsiUtilBase.getPsiFileInEditor(editor, myProject);
    if (file == null) return null;

    Map<TemplateImpl, String> template2argument =
        findMatchingTemplates(file, editor, shortcutChar, TemplateSettings.getInstance());

    List<CustomLiveTemplate> customCandidates =
        ContainerUtil.findAll(
            CustomLiveTemplate.EP_NAME.getExtensions(),
            customLiveTemplate ->
                shortcutChar == customLiveTemplate.getShortcut()
                    && (editor.getCaretModel().getCaretCount() <= 1
                        || supportsMultiCaretMode(customLiveTemplate)));
    if (!customCandidates.isEmpty()) {
      int caretOffset = editor.getCaretModel().getOffset();
      PsiFile fileCopy = insertDummyIdentifierIfNeeded(file, caretOffset, caretOffset, "");
      Document document = editor.getDocument();

      for (final CustomLiveTemplate customLiveTemplate : customCandidates) {
        if (isApplicable(customLiveTemplate, editor, fileCopy)) {
          final String key =
              customLiveTemplate.computeTemplateKey(new CustomTemplateCallback(editor, fileCopy));
          if (key != null) {
            int offsetBeforeKey = caretOffset - key.length();
            CharSequence text = document.getImmutableCharSequence();
            if (template2argument == null
                || !containsTemplateStartingBefore(
                    template2argument, offsetBeforeKey, caretOffset, text)) {
              return () -> customLiveTemplate.expand(key, new CustomTemplateCallback(editor, file));
            }
          }
        }
      }
    }

    return startNonCustomTemplates(template2argument, editor, processor);
  }
    @Override
    public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
      SelectionModel selectionModel = editor.getSelectionModel();
      if (!selectionModel.hasSelection()) {
        selectionModel.selectLineAtCaret();
      }

      ZenCodingTemplate emmetCustomTemplate =
          CustomLiveTemplate.EP_NAME.findExtension(ZenCodingTemplate.class);
      if (emmetCustomTemplate != null) {
        new WrapWithCustomTemplateAction(
                emmetCustomTemplate, editor, file, ContainerUtil.newHashSet())
            .actionPerformed(null);
      } else if (!ApplicationManager.getApplication().isUnitTestMode()) {
        HintManager.getInstance()
            .showErrorHint(editor, "Cannot invoke Surround with Emmet in the current context");
      }
    }