private static void doAnnotate(@NotNull final Editor editor,
                                 @NotNull final Project project,
                                 @NotNull final FileAnnotation fileAnnotation,
                                 @NotNull final AbstractVcs vcs,
                                 @NotNull final UpToDateLineNumberProvider upToDateLineNumbers,
                                 final boolean warnAboutSuspiciousAnnotations) {
    ThreadingAssertions.assertEventDispatchThread();
    if (project.isDisposed() || editor.isDisposed()) return;

    if (warnAboutSuspiciousAnnotations) {
      int expectedLines = Math.max(upToDateLineNumbers.getLineCount(), 1);
      int actualLines = Math.max(fileAnnotation.getLineCount(), 1);
      if (Math.abs(expectedLines - actualLines) > 1) { // 1 - for different conventions about files ending with line separator
        LOG.warn("Unexpected annotation lines number. Expected: " + expectedLines + ", actual: " + actualLines);
        editor.setHeaderComponent(new MyEditorNotificationPanel(editor, vcs, () -> {
          doAnnotate(editor, project, fileAnnotation, vcs, upToDateLineNumbers, false);
        }));
        return;
      }
    }

    fileAnnotation.setCloser(() -> UIUtil.invokeLaterIfNeeded(() -> {
      if (project.isDisposed()) return;
      closeVcsAnnotations(editor);
    }));

    fileAnnotation.setReloader(newFileAnnotation -> {
      if (project.isDisposed()) return;
      if (hasVcsAnnotations(editor)) {
        if (newFileAnnotation != null) {
          assert Comparing.equal(fileAnnotation.getFile(), newFileAnnotation.getFile());
          doAnnotate(editor, project, newFileAnnotation, vcs, upToDateLineNumbers, false);
        }
        else {
          DataContext dataContext = DataManager.getInstance().getDataContext(editor.getComponent());
          AnActionEvent event = AnActionEvent.createFromDataContext(ActionPlaces.UNKNOWN, null, dataContext);
          Provider provider = getProvider(event);

          if (provider != null && provider.isEnabled(event) && !provider.isSuspended(event)) {
            provider.perform(event, true);
          }
          else {
            closeVcsAnnotations(editor);
          }
        }
      }
    });

    if (fileAnnotation.isClosed()) return;


    Disposable disposable = new Disposable() {
      @Override
      public void dispose() {
        fileAnnotation.dispose();
      }
    };

    VcsAnnotationLocalChangesListener changesListener = ProjectLevelVcsManager.getInstance(project).getAnnotationLocalChangesListener();
    changesListener.registerAnnotation(fileAnnotation);
    Disposer.register(disposable, new Disposable() {
      @Override
      public void dispose() {
        changesListener.unregisterAnnotation(fileAnnotation);
      }
    });

    closeVcsAnnotations(editor);

    final List<AnnotationFieldGutter> gutters = new ArrayList<>();
    final AnnotationSourceSwitcher switcher = fileAnnotation.getAnnotationSourceSwitcher();

    final AnnotationPresentation presentation = new AnnotationPresentation(fileAnnotation, upToDateLineNumbers, switcher, disposable);
    presentation.addAction(new ShowDiffFromAnnotation(project, fileAnnotation));
    presentation.addAction(new CopyRevisionNumberFromAnnotateAction(fileAnnotation));
    presentation.addAction(Separator.getInstance());

    final Couple<Map<VcsRevisionNumber, Color>> bgColorMap = computeBgColors(fileAnnotation, editor);
    final Map<VcsRevisionNumber, Integer> historyIds = computeLineNumbers(fileAnnotation);

    gutters.add(new FillerColumn(fileAnnotation, presentation, bgColorMap));
    if (switcher != null) {
      switcher.switchTo(switcher.getDefaultSource());
      final LineAnnotationAspect revisionAspect = switcher.getRevisionAspect();
      final CurrentRevisionAnnotationFieldGutter currentRevisionGutter =
        new CurrentRevisionAnnotationFieldGutter(fileAnnotation, revisionAspect, presentation, bgColorMap);
      final MergeSourceAvailableMarkerGutter mergeSourceGutter =
        new MergeSourceAvailableMarkerGutter(fileAnnotation, presentation, bgColorMap);

      SwitchAnnotationSourceAction switchAction = new SwitchAnnotationSourceAction(switcher);
      presentation.addAction(switchAction);
      switchAction.addSourceSwitchListener(currentRevisionGutter);
      switchAction.addSourceSwitchListener(mergeSourceGutter);

      currentRevisionGutter.accept(switcher.getDefaultSource());
      mergeSourceGutter.accept(switcher.getDefaultSource());

      gutters.add(currentRevisionGutter);
      gutters.add(mergeSourceGutter);
    }

    List<LineAnnotationAspect> aspects = Arrays.asList(fileAnnotation.getAspects());
    List<LineAnnotationAspect> fromExt =
      ContainerUtil.mapNotNull(AnnotationGutterColumnProvider.EP_NAME.getExtensions(), extension -> extension.createColumn(fileAnnotation));
    for (LineAnnotationAspect aspect : ContainerUtil.concat(aspects, fromExt)) {
      gutters.add(new AspectAnnotationFieldGutter(fileAnnotation, aspect, presentation, bgColorMap));
    }


    if (historyIds != null) {
      gutters.add(new HistoryIdColumn(fileAnnotation, presentation, bgColorMap, historyIds));
    }
    if (!ExperimentalUI.isNewUI()) {
      gutters.add(new HighlightedAdditionalColumn(fileAnnotation, presentation, bgColorMap));
    }
    final AnnotateActionGroup actionGroup = new AnnotateActionGroup(fileAnnotation, gutters, bgColorMap);
    presentation.addAction(actionGroup, 1);
    gutters.add(new ExtraFieldGutter(fileAnnotation, presentation, bgColorMap, actionGroup));

    presentation.addAction(new AnnotateCurrentRevisionAction(fileAnnotation, vcs));
    presentation.addAction(new AnnotatePreviousRevisionAction(fileAnnotation, vcs));
    addActionsFromExtensions(presentation, fileAnnotation);

    for (AnnotationFieldGutter gutter : gutters) {
      final AnnotationGutterLineConvertorProxy proxy = gutter instanceof TextAnnotationGutterProvider.Filler
                                                       ? new AnnotationGutterLineConvertorProxy.Filler(upToDateLineNumbers, gutter)
                                                       : new AnnotationGutterLineConvertorProxy(upToDateLineNumbers, gutter);
      if (gutter.isGutterAction()) {
        editor.getGutter().registerTextAnnotation(proxy, proxy);
      }
      else {
        editor.getGutter().registerTextAnnotation(proxy);
      }
    }

    InlineDiffFromAnnotation.showDiffOnHover(editor, fileAnnotation, presentation, disposable);
  }
private static void doAnnotate(@NotNull final Editor editor,
                                 @NotNull final Project project,
                                 @NotNull final FileAnnotation fileAnnotation,
                                 @NotNull final AbstractVcs vcs,
                                 @NotNull final UpToDateLineNumberProvider upToDateLineNumbers,
                                 final boolean warnAboutSuspiciousAnnotations)