@Override
  public Result preprocessEnter(@NotNull PsiFile file,
                                @NotNull Editor editor,
                                @NotNull Ref<Integer> caretOffset,
                                @NotNull Ref<Integer> caretAdvance,
                                @NotNull DataContext dataContext,
                                EditorActionHandler originalHandler) {
    int offset = caretOffset.get();
    if (editor instanceof EditorWindow) {
      file = InjectedLanguageManager.getInstance(file.getProject()).getTopLevelFile(file);
      editor = InjectedLanguageUtil.getTopLevelEditor(editor);
      offset = editor.getCaretModel().getOffset();
    }
    if (!(file instanceof PyAstFile)) {
      return Result.Continue;
    }
    final Boolean isSplitLine = DataManager.getInstance().loadFromDataContext(dataContext, SplitLineAction.SPLIT_LINE_KEY);
    if (isSplitLine != null) {
      return Result.Continue;
    }
    final Document doc = editor.getDocument();
    PsiDocumentManager.getInstance(file.getProject()).commitDocument(doc);
    final PsiElement element = file.findElementAt(offset);
    final PsiElement prevElement = offset > 0 ? file.findElementAt(offset - 1) : null;
    CodeInsightSettings codeInsightSettings = CodeInsightSettings.getInstance();
    if (codeInsightSettings.JAVADOC_STUB_ON_ENTER) {
      PsiElement comment = element;
      if (comment == null && offset != 0) {
        comment = prevElement;
      }
      int expectedStringStart = editor.getCaretModel().getOffset() - 3; // """ or '''
      if (comment != null) {
        final DocstringState state = canGenerateDocstring(comment, expectedStringStart, doc);
        if (state != DocstringState.NONE) {
          insertDocStringStub(editor, comment, state);
          return Result.Continue;
        }
      }
    }

    if (element == null) {
      return Result.Continue;
    }

    final ASTNode node = element.getNode();
    PsiElement elementParent = element.getParent();
    final IElementType nodeType = node.getElementType();
    if (nodeType == PyTokenTypes.LPAR) elementParent = elementParent.getParent();
    if (elementParent instanceof PyAstParenthesizedExpression || elementParent instanceof PyAstGeneratorExpression) return Result.Continue;

    final PyAstStringElement stringElement = PsiTreeUtil.getParentOfType(element, PyAstStringElement.class, false);
    if (stringElement == null && prevElement == element) {
      return Result.Continue;
    }
    
    if (stringElement != null && (!stringElement.isFormatted() ||
                                  nodeType == PyTokenTypes.FSTRING_TEXT ||
                                  // Caret should be right before the opening brace of an f-string fragment 
                                  nodeType == PyTokenTypes.FSTRING_FRAGMENT_START || 
                                  nodeType == PyTokenTypes.FSTRING_END)) {
      if (stringElement.isTripleQuoted() || nodeType == PyTokenTypes.DOCSTRING) {
        return Result.Continue;
      }
      if (prevElement != null && PsiTreeUtil.isAncestor(stringElement, prevElement, false)) {
        
        if (stringElement.getTextOffset() + stringElement.getPrefixLength() >= offset) {
          return Result.Continue;
        }

        final String pref = stringElement.getPrefix();
        final String quote = stringElement.getQuote();

        // Don't split in the middle of an escape sequence
        final boolean afterBackslash = "\\".equals(doc.getText(TextRange.from(offset - 1, 1)));
        final boolean isEscapedQuote = quote.equals(doc.getText(TextRange.from(offset, 1))) && afterBackslash;
        final boolean isEscapedBackslash = "\\".equals(doc.getText(TextRange.from(offset - 2, 1))) && afterBackslash;
        if (afterBackslash && !isEscapedQuote && !isEscapedBackslash) return Result.Continue;

        myPostprocessShift = pref.length() + quote.length();

        boolean parenthesiseOnEnter = PyCodeInsightSettings.getInstance().PARENTHESISE_ON_ENTER;
        final String delimiter = parenthesiseOnEnter ? "" : " \\";

        // TODO check for a non-parenthesized sequence pattern here
        if (PsiTreeUtil.getParentOfType(stringElement, PyEditorHandlerConfig.IMPLICIT_WRAP_CLASSES) != null) {
          doc.insertString(offset, quote + pref + quote);
          caretOffset.set(caretOffset.get() + 1);
        }
        else {
          int insertionOffset = offset;
          if (isEscapedQuote) {
            // Preserve the escaped quote, split after it
            caretOffset.set(caretOffset.get() + 1);
            insertionOffset++;
          }
          if (parenthesiseOnEnter) {
            parenthesise(stringElement, doc);
            caretOffset.set(caretOffset.get() + 1);
            insertionOffset++;
          }
          doc.insertString(insertionOffset, quote + delimiter + pref + quote);
          caretOffset.set(caretOffset.get() + delimiter.length() + 1);
        }
        return Result.Continue;
      }
    }

    return checkInsertBackslash(file, caretOffset, dataContext, offset, doc);
  }
@Override
  public Result preprocessEnter(@NotNull PsiFile file,
                                @NotNull Editor editor,
                                @NotNull Ref<Integer> caretOffset,
                                @NotNull Ref<Integer> caretAdvance,
                                @NotNull DataContext dataContext,
                                EditorActionHandler originalHandler)