void (Function<Point, @Nullable JBPopup> popupPresenter) { EDT.assertIsEdt(); myInsideShow = true; try { if (myEditor.isDisposed() || !isCurrentRangeValid()) { hideHint(); return; } hideCurrentHint(); createHighlighter(); setHighlighterAttributes(); // align the popup with the bottom of the line Point point = myEditor.visualPositionToXY(myEditor.xyToVisualPosition(myPoint)); point.translate(0, myEditor.getLineHeight()); JBPopup popup = popupPresenter.apply(point); if (popup != null) { myCurrentPopup = popup; myEditor.getScrollingModel().addVisibleAreaListener(e -> { if (!Objects.equals(e.getOldRectangle(), e.getNewRectangle())) { hideCurrentHint(); } }, popup); myEditor.getCaretModel().addCaretListener(new CaretListener() { @Override public void caretPositionChanged(@NotNull CaretEvent event) { hideCurrentHint(); } @Override public void caretAdded(@NotNull CaretEvent event) { hideCurrentHint(); } @Override public void caretRemoved(@NotNull CaretEvent event) { hideCurrentHint(); } }, popup); popup.addListener(new JBPopupListener() { @Override public void onClosed(@NotNull LightweightWindowEvent event) { processHintHidden(); } }); setCurrentEditorHint(); } } finally { myInsideShow = false; } }