private @NotNull TemplateState startTemplate(final Editor editor,
                             final String selectionString,
                             final Template template,
                             boolean inSeparateCommand,
                             TemplateEditingListener listener,
                             final PairProcessor<? super String, ? super String> processor,
                             final Map<String, String> predefinedVarValues) {
    final TemplateState templateState = initTemplateState(editor);

    //noinspection unchecked
    templateState.getProperties().put(ExpressionContext.SELECTION, selectionString);

    if (listener != null) {
      templateState.addTemplateStateListener(listener);
    }
    Runnable r = () -> {
      if (selectionString != null) {
        templateState.performWrite(() -> EditorModificationUtilEx.deleteSelectedText(editor));
      }
      else {
        editor.getSelectionModel().removeSelection();
      }
      TemplateImpl substitutedTemplate = substituteTemplate((TemplateImpl)template, editor);

      templateState.start(substitutedTemplate, processor, predefinedVarValues);
    };
    if (inSeparateCommand && templateState.requiresWriteAction()) {
      CommandProcessor.getInstance().executeCommand(myProject, r, AnalysisBundle.message("insert.code.template.command"), null);
    }
    else {
      r.run();
    }

    if (shouldSkipInTests()) {
      if (!templateState.isFinished()) templateState.gotoEnd(false);
    }
    return templateState;
  }
private @NotNull TemplateState startTemplate(final Editor editor,
                             final String selectionString,
                             final Template template,
                             boolean inSeparateCommand,
                             TemplateEditingListener listener,
                             final PairProcessor<? super String, ? super String> processor,
                             final Map<String, String> predefinedVarValues)