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;
 }
 public static boolean isApplicable(
     @NotNull CustomLiveTemplate customLiveTemplate,
     @NotNull Editor editor,
     @NotNull PsiFile file,
     boolean wrapping) {
   return customLiveTemplate.isApplicable(
       file, CustomTemplateCallback.getOffset(editor), wrapping);
 }
  @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);
  }