@Nullable
    public GutterIconRenderer createRenderer() {
      myCtrlPressed = myViewer.getModifierProvider().isCtrlPressed();

      boolean isEditable = DiffUtil.isEditable(myViewer.getEditor(mySide));
      boolean isOtherEditable = DiffUtil.isEditable(myViewer.getEditor(mySide.other()));
      boolean isAppendable =
          myFragment.getStartLine1() != myFragment.getEndLine1()
              && myFragment.getStartLine2() != myFragment.getEndLine2();

      if (isOtherEditable && isEditable) {
        if (myCtrlPressed && isAppendable) {
          return createAppendRenderer(mySide);
        } else {
          return createApplyRenderer(mySide);
        }
      } else if (isEditable) {
        return createRevertRenderer(mySide);
      } else if (isOtherEditable) {
        if (isAppendable) {
          return createAppendRenderer(mySide);
        }
      }
      return null;
    }
  @Nullable
  State processBaseChange(int oldLine1, int oldLine2, int shift) {
    int line1 = getStartLine();
    int line2 = getEndLine();

    UpdatedLineRange newRange =
        DiffUtil.updateRangeOnModification(line1, line2, oldLine1, oldLine2, shift);

    boolean rangeAffected =
        newRange.damaged
            || (oldLine2 >= line1
                && oldLine1 <= line2); // RangeMarker can be updated in a different way
    State oldState = rangeAffected ? storeState() : null;

    if (newRange.startLine == newRange.endLine
        && getDiffType() == TextDiffType.DELETED
        && !isResolved()) {
      if (oldState == null) oldState = storeState();
      myViewer.markChangeResolved(this);
    }

    setStartLine(newRange.startLine);
    setEndLine(newRange.endLine);

    return oldState;
  }
 @Nullable
 private GutterIconRenderer createIconRenderer(
     @NotNull final Side sourceSide,
     @NotNull final String tooltipText,
     @NotNull final Icon icon,
     @NotNull final Runnable perform) {
   if (!DiffUtil.isEditable(myViewer.getEditor(sourceSide.other()))) return null;
   return new DiffGutterRenderer(icon, tooltipText) {
     @Override
     protected void performAction(AnActionEvent e) {
       if (!myIsValid) return;
       final Project project = e.getProject();
       final Document document = myViewer.getEditor(sourceSide.other()).getDocument();
       DiffUtil.executeWriteCommand(
           document,
           project,
           "Replace change",
           new Runnable() {
             @Override
             public void run() {
               perform.run();
             }
           });
     }
   };
 }
  private void createHighlighter(@NotNull Side side, boolean ignored) {
    Editor editor = myViewer.getEditor(side);

    TextDiffType type = DiffUtil.getLineDiffType(myFragment);
    int startLine = side.getStartLine(myFragment);
    int endLine = side.getEndLine(myFragment);

    myHighlighters.addAll(
        DiffDrawUtil.createHighlighter(editor, startLine, endLine, type, ignored));
    myHighlighters.addAll(DiffDrawUtil.createLineMarker(editor, startLine, endLine, type, false));
  }
  private void createInlineHighlighter(@NotNull DiffFragment fragment, @NotNull Side side) {
    int start = side.getStartOffset(fragment);
    int end = side.getEndOffset(fragment);
    TextDiffType type = DiffUtil.getDiffType(fragment);

    int startOffset = side.getStartOffset(myFragment);
    start += startOffset;
    end += startOffset;

    Editor editor = myViewer.getEditor(side);
    myHighlighters.addAll(DiffDrawUtil.createInlineHighlighter(editor, start, end, type));
  }
 @Nullable
 private GutterIconRenderer createAppendRenderer(@NotNull final Side side) {
   return createIconRenderer(
       side,
       "Append",
       DiffUtil.getArrowDownIcon(side),
       new Runnable() {
         @Override
         public void run() {
           myViewer.appendChange(SimpleDiffChange.this, side);
         }
       });
 }
 @Nullable
 private GutterIconRenderer createIconRenderer(
     @NotNull final String text,
     @NotNull final Icon icon,
     boolean ctrlClickVisible,
     @NotNull final Runnable perform) {
   final String tooltipText =
       DiffUtil.createTooltipText(text, ctrlClickVisible ? CTRL_CLICK_TO_RESOLVE : null);
   return new DiffGutterRenderer(icon, tooltipText) {
     @Override
     protected void performAction(AnActionEvent e) {
       perform.run();
     }
   };
 }
 @Nullable
 private GutterIconRenderer createApplyRenderer(@NotNull final Side side, final boolean modifier) {
   if (isResolved(side)) return null;
   Icon icon =
       isOnesideAppliedConflict() ? DiffUtil.getArrowDownIcon(side) : DiffUtil.getArrowIcon(side);
   return createIconRenderer(
       DiffBundle.message("merge.dialog.apply.change.action.name"),
       icon,
       isConflict(),
       new Runnable() {
         @Override
         public void run() {
           myViewer.executeMergeCommand(
               "Accept change",
               Collections.singletonList(TextMergeChange.this),
               new Runnable() {
                 @Override
                 public void run() {
                   myViewer.replaceChange(TextMergeChange.this, side, modifier);
                 }
               });
         }
       });
 }
  private void createInnerHighlighter(@NotNull ThreeSide side) {
    if (isResolved(side)) return;
    if (myInnerFragments == null) return;

    Editor editor = myViewer.getEditor(side);
    int start =
        DiffUtil.getLinesRange(editor.getDocument(), getStartLine(side), getEndLine(side))
            .getStartOffset();
    for (MergeWordFragment fragment : myInnerFragments) {
      int innerStart = start + fragment.getStartOffset(side);
      int innerEnd = start + fragment.getEndOffset(side);
      myInnerHighlighters.addAll(
          DiffDrawUtil.createInlineHighlighter(editor, innerStart, innerEnd, getDiffType()));
    }
  }
 public void setContents(DiffContent content1, DiffContent content2) {
   LOG.assertTrue(content1 != null && content2 != null);
   LOG.assertTrue(!myDisposed);
   myData.setContents(content1, content2);
   Project project = myData.getProject();
   FileType[] types = DiffUtil.chooseContentTypes(new DiffContent[] {content1, content2});
   VirtualFile beforeFile = content1.getFile();
   VirtualFile afterFile = content2.getFile();
   String path = myDiffRequest == null ? null : myDiffRequest.getWindowTitle();
   myLeftSide.setHighlighterFactory(
       createHighlighter(types[0], beforeFile, afterFile, path, project));
   myRightSide.setHighlighterFactory(
       createHighlighter(types[1], afterFile, beforeFile, path, project));
   setSplitterProportion(content1, content2);
   rediff();
   if (myIsRequestFocus) {
     myPanel.requestScrollEditors();
   }
 }
  public boolean processChange(int oldLine1, int oldLine2, int shift, @NotNull Side side) {
    int line1 = getStartLine(side);
    int line2 = getEndLine(side);
    int sideIndex = side.getIndex();

    DiffUtil.UpdatedLineRange newRange =
        DiffUtil.updateRangeOnModification(line1, line2, oldLine1, oldLine2, shift);
    myLineStartShifts[sideIndex] += newRange.startLine - line1;
    myLineEndShifts[sideIndex] += newRange.endLine - line2;

    if (newRange.damaged) {
      for (MyGutterOperation operation : myOperations) {
        operation.dispose();
      }
      myOperations.clear();

      myIsValid = false;
    }

    return newRange.damaged;
  }
  @Nullable
  private MyGutterOperation createOperation(@NotNull ThreeSide side, @NotNull OperationType type) {
    if (isResolved(side)) return null;

    EditorEx editor = myViewer.getEditor(side);
    Document document = editor.getDocument();

    int line = getStartLine(side);
    int offset =
        line == DiffUtil.getLineCount(document)
            ? document.getTextLength()
            : document.getLineStartOffset(line);

    RangeHighlighter highlighter =
        editor
            .getMarkupModel()
            .addRangeHighlighter(
                offset,
                offset,
                HighlighterLayer.ADDITIONAL_SYNTAX,
                null,
                HighlighterTargetArea.LINES_IN_RANGE);
    return new MyGutterOperation(side, highlighter, type);
  }
  public boolean isSelectedByLine(int line, @NotNull Side side) {
    int line1 = getStartLine(side);
    int line2 = getEndLine(side);

    return DiffUtil.isSelectedByLine(line, line1, line2);
  }
 @NotNull
 public TextDiffType getDiffType() {
   return DiffUtil.getLineDiffType(myFragment);
 }