@Override
    public void beforeDocumentChange(@NotNull DocumentEvent e) {
      if (myDuringOnesideDocumentModification) return;
      ChangedBlockData blockData = myModel.getData();
      if (blockData == null) {
        LOG.warn("oneside beforeDocumentChange - model is invalid");
        return;
      }
      // TODO: modify Document guard range logic - we can handle case, when whole read-only block is modified (ex: my replacing selection).

      try {
        myDuringTwosideDocumentModification = true;

        Document twosideDocument = getDocument(myMasterSide);

        LineCol onesideStartPosition = LineCol.fromOffset(myDocument, e.getOffset());
        LineCol onesideEndPosition = LineCol.fromOffset(myDocument, e.getOffset() + e.getOldLength());

        int line1 = onesideStartPosition.line;
        int line2 = onesideEndPosition.line + 1;
        int shift = DiffUtil.countLinesShift(e);

        int twosideStartLine = transferLineFromOnesideStrict(myMasterSide, onesideStartPosition.line);
        int twosideEndLine = transferLineFromOnesideStrict(myMasterSide, onesideEndPosition.line);
        if (twosideStartLine == -1 || twosideEndLine == -1) {
          // this should never happen
          logDebugInfo(e, onesideStartPosition, onesideEndPosition, twosideStartLine, twosideEndLine);
          markSuppressEditorTyping();
          return;
        }

        int twosideStartOffset = twosideDocument.getLineStartOffset(twosideStartLine) + onesideStartPosition.column;
        int twosideEndOffset = twosideDocument.getLineStartOffset(twosideEndLine) + onesideEndPosition.column;
        twosideDocument.replaceString(twosideStartOffset, twosideEndOffset, e.getNewFragment());

        for (UnifiedDiffChange change : blockData.getDiffChanges()) {
          change.processChange(line1, line2, shift);
        }

        LineNumberConvertor masterConvertor = blockData.getLineNumberConvertor(myMasterSide);
        LineNumberConvertor slaveConvertor = blockData.getLineNumberConvertor(myMasterSide.other());
        masterConvertor.handleMasterChange(line1, line2, shift, true);
        slaveConvertor.handleMasterChange(line1, line2, shift, false);
      }
      finally {
        // TODO: we can avoid marking state out-of-date in some simple cases (like in SimpleDiffViewer)
        // but this will greatly increase complexity, so let's wait if it's actually required by users
        markStateIsOutOfDate();

        scheduleRediff();

        myDuringTwosideDocumentModification = false;
      }
    }
@Override
    public void beforeDocumentChange(@NotNull DocumentEvent e)