private ActionCallback doFetchDocInfo(@NotNull DocumentationComponent component,
                                        @NotNull DocumentationCollector collector) {
    ActionCallback callback = collector.actionCallback != null ? collector.actionCallback : createActionCallback();

    boolean wasEmpty = component.isEmpty();
    if (wasEmpty) {
      component.setText(CodeInsightBundle.message("javadoc.fetching.progress"), null, collector.provider);
    }

    ModalityState modality = ModalityState.defaultModalityState();

    String precalculatedDocumentation = myPrecalculatedDocumentation;
    myPrecalculatedDocumentation = null;
    myUpdateDocAlarm.addRequest(() -> {
      if (myProject.isDisposed()) return;
      LOG.debug("Started fetching documentation...");

      PsiElement element = collector.getElement(true);
      if (element == null || !ReadAction.compute(() -> element.isValid())) {
        LOG.debug("Element for which documentation was requested is not available anymore");
        ModalityUiUtil.invokeLaterIfNeeded(ModalityState.any(), () -> {
          component.setText(CodeInsightBundle.message("no.documentation.found"), null, collector.provider);
        });
        callback.setDone();
        return;
      }

      Language elementLanguage = ReadAction.compute(() -> element.getLanguage());
      DocToolWindowManager toolWindowManager = DocToolWindowManager.LANGUAGE_MANAGER.forLanguage(elementLanguage);
      if (toolWindowManager != null) {
        if (collector.onAutoUpdate && !toolWindowManager.isAutoUpdateAvailable()) {
          callback.setDone();
          return;
        }
        if (myToolWindow != null) {
          toolWindowManager.prepareForShowDocumentation(myToolWindow, this);
        }
      }
      component.startWait();

      final @Nls String text;
      final DocumentationProvider provider;
      try {
        if (precalculatedDocumentation != null) {
          LOG.debug("Setting precalculated documentation:\n", precalculatedDocumentation);
          text = precalculatedDocumentation;
          PsiElement originalElement = getOriginalElement(collector, element);
          provider = ReadAction.compute(() -> getProviderFromElement(element, originalElement));
        }
        else {
          text = collector.getDocumentation();
          provider = collector.provider;
        }
      }
      catch (Throwable e) {
        LOG.info(e);
        ModalityUiUtil.invokeLaterIfNeeded(ModalityState.any(), () -> {
          //noinspection InstanceofCatchParameter
          String message = e instanceof IndexNotReadyException
                           ? CodeInsightBundle.message("documentation.message.documentation.is.not.available")
                           : CodeInsightBundle.message("javadoc.external.fetch.error.message");
          component.setText(message, null, collector.provider);
          component.clearHistory();
          callback.setDone();
        });
        return;
      }

      LOG.debug("Documentation fetched successfully:\n", text);

      final @Nls String decoratedText = ReadAction.compute(() -> {
        if (text == null) {
          return decorate(element, CodeInsightBundle.message("no.documentation.found"), null, provider);
        }
        else if (text.isEmpty()) {
          return null;
        }
        else if (precalculatedDocumentation != null) {
          return text; // text == precalculatedDocumentation in this case; don't decorate it
        }
        else {
          return decorate(element, text, collector.effectiveUrl, provider);
        }
      });

      PsiDocumentManager.getInstance(myProject).performLaterWhenAllCommitted(modality, () -> {
        if (!element.isValid()) {
          LOG.debug("Element for which documentation was requested is not valid");
          callback.setDone();
          return;
        }
        if (text == null) {
          component.setText(decoratedText, element, provider);
        }
        else if (text.isEmpty()) {
          component.setText(component.getDecoratedText(), element, provider);
        }
        else {
          component.setData(element, decoratedText, collector.effectiveUrl, collector.ref, provider);
        }
        if (wasEmpty) {
          component.clearHistory();
        }
        callback.setDone();
      });
    }, 10);
    return callback;
  }
private ActionCallback doFetchDocInfo(@NotNull DocumentationComponent component,
                                        @NotNull DocumentationCollector collector)