@Override
    public void onLinkFollowed(@NotNull Project project,
                               @NotNull VirtualFile file,
                               @NotNull Editor targetEditor,
                               @Nullable Editor originalEditor) {
      if (DumbService.isDumb(project)) return; // may need to resolve refs
      Document document = FileDocumentManager.getInstance().getDocument(file);
      if (document == null || document.getLineCount() <= myLineNumber) return;
      if (!PsiDocumentManager.getInstance(project).isCommitted(document)) return;
      int startOffset = document.getLineStartOffset(myLineNumber);
      int endOffset = document.getLineEndOffset(myLineNumber);

      long stamp = document.getModificationStamp();
      ReadAction.nonBlocking(() -> computeLinkInfo(project, file, startOffset, endOffset, targetEditor, originalEditor))
        .expireWhen(() -> project.isDisposed() || targetEditor.isDisposed() || document.getModificationStamp() != stamp)
        .finishOnUiThread(ModalityState.nonModal(), info -> {
          if (info == null) return;
          if (info.myTarget != null) {
            TextRange range = info.myTarget.getTextRange();
            targetEditor.getCaretModel().moveToOffset(range.getStartOffset());
          }

          if (info.myAction != null && !ApplicationManager.getApplication().isUnitTestMode()) {
            displayAnalysisAction(project, info, targetEditor);
          }
        })
        .submit(AppExecutorUtil.getAppExecutorService());
    }
@Override
    public void onLinkFollowed(@NotNull Project project,
                               @NotNull VirtualFile file,
                               @NotNull Editor targetEditor,
                               @Nullable Editor originalEditor)