@NotNull
  public static Promise<@Nullable XLineBreakpoint> toggleAndReturnLineBreakpoint(@NotNull final Project project,
                                                                                 @NotNull List<? extends XLineBreakpointType> types,
                                                                                 @NotNull final XSourcePosition position,
                                                                                 boolean selectVariantByPositionColumn,
                                                                                 final boolean temporary,
                                                                                 @Nullable final Editor editor,
                                                                                 boolean canRemove) {
    final VirtualFile file = position.getFile();
    final int line = position.getLine();
    final XBreakpointManager breakpointManager = XDebuggerManager.getInstance(project).getBreakpointManager();

    Promise<List<? extends XLineBreakpointType.XLineBreakpointVariant>> variantsAsync = getLineBreakpointVariants(project, types, position);
    if (areInlineBreakpointsEnabled(file)) {
      return variantsAsync.then(variantsWithAll -> {
        var variants = variantsWithAll.stream().filter(v -> v.shouldUseAsInlineVariant()).toList();
        if (variants.isEmpty()) {
          LOG.error("Unexpected empty variants");
          return null;
        }

        var breakpoints = types.stream().flatMap(t -> breakpointManager.findBreakpointsAtLine(t, file, line).stream()).toList();

        XLineBreakpointType.XLineBreakpointVariant variant;
        if (selectVariantByPositionColumn) {
          var breakpointOrVariant = getBestMatchingBreakpoint(position.getOffset(),
                                                              Stream.concat(breakpoints.stream(), variants.stream()).iterator(),
                                                              o ->
                                                                o instanceof XLineBreakpoint b
                                                                ? b.getType().getHighlightRange(b)
                                                                : ((XLineBreakpointType.XLineBreakpointVariant)o).getHighlightRange());

          if (breakpointOrVariant instanceof XLineBreakpoint existingBreakpoint) {
            if (!temporary && canRemove) {
              removeBreakpointWithConfirmation(project, existingBreakpoint);
            }
            return null;
          }

          variant = (XLineBreakpointType.XLineBreakpointVariant)breakpointOrVariant;
        }
        else {
          if (!breakpoints.isEmpty()) {
            if (!temporary && canRemove) {
              removeBreakpointsWithConfirmation(project, breakpoints);
            }
            return null;
          }

          variant = variants.stream().max(Comparator.comparing(v -> v.getPriority(project))).get();
        }

        return addLineBreakpoint(breakpointManager, variant, file, line, temporary);
      });
    }

    for (XLineBreakpointType type : types) {
      XLineBreakpoint breakpoint = breakpointManager.findBreakpointAtLine(type, file, line);
      if (breakpoint != null) {
        if (!temporary && canRemove) {
          removeBreakpointWithConfirmation(project, breakpoint);
        }
        return resolvedPromise();
      }
    }

    return variantsAsync.thenAsync(variants -> {
      assert !variants.isEmpty();
      final AsyncPromise<XLineBreakpoint> res = new AsyncPromise<>();
      ModalityUiUtil.invokeLaterIfNeeded(ModalityState.defaultModalityState(), () -> {
        for (XLineBreakpointType<?> type : types) {
          if (breakpointManager.findBreakpointAtLine(type, file, line) != null) {
            return;
          }
        }
        RelativePoint relativePoint = editor != null ? DebuggerUIUtil.getPositionForPopup(editor, line) : null;
        if (variants.size() > 1 && relativePoint != null) {
          class MySelectionListener implements ListSelectionListener {
            RangeHighlighter myHighlighter = null;

            @Override
            public void valueChanged(ListSelectionEvent e) {
              if (!e.getValueIsAdjusting()) {
                updateHighlighter(((JList<?>)e.getSource()).getSelectedValue());
              }
            }

            public void initialSet(Object value) {
              if (myHighlighter == null) {
                updateHighlighter(value);
              }
            }

            void updateHighlighter(Object value) {
              clearHighlighter();
              if (value instanceof XLineBreakpointType.XLineBreakpointVariant) {
                TextRange range = ((XLineBreakpointType.XLineBreakpointVariant)value).getHighlightRange();
                TextRange lineRange = DocumentUtil.getLineTextRange(editor.getDocument(), line);
                if (range == null) {
                  range = lineRange;
                }
                if (!range.isEmpty() && range.intersects(lineRange)) {
                  myHighlighter = editor.getMarkupModel().addRangeHighlighter(
                    DebuggerColors.BREAKPOINT_ATTRIBUTES, range.getStartOffset(), range.getEndOffset(), DebuggerColors.BREAKPOINT_HIGHLIGHTER_LAYER,
                    HighlighterTargetArea.EXACT_RANGE);
                }
              }
            }

            private void clearHighlighter() {
              if (myHighlighter != null) {
                myHighlighter.dispose();
              }
            }
          }

          final int defaultIndex = getIndexOfBestMatchingInlineVariant(position.getOffset(), variants);

          final MySelectionListener selectionListener = new MySelectionListener();
          BaseListPopupStep<XLineBreakpointType.XLineBreakpointVariant> step =
            new BaseListPopupStep<>(XDebuggerBundle.message("popup.title.set.breakpoint"), variants) {
              @NotNull
              @Override
              public String getTextFor(XLineBreakpointType.XLineBreakpointVariant value) {
                return value.getText();
              }

              @Override
              public Icon getIconFor(XLineBreakpointType.XLineBreakpointVariant value) {
                return value.getIcon();
              }

              @Override
              public void canceled() {
                selectionListener.clearHighlighter();
                res.cancel();
              }

              @Override
              public PopupStep<?> onChosen(final XLineBreakpointType.XLineBreakpointVariant selectedValue, boolean finalChoice) {
                selectionListener.clearHighlighter();
                addLineBreakpoint(res, breakpointManager, selectedValue, file, line, temporary);
                return FINAL_CHOICE;
              }

              @Override
              public int getDefaultOptionIndex() {
                return defaultIndex;
              }
            };
          ListPopupImpl popup = new ListPopupImpl(project, step) {
            @Override
            protected void afterShow() {
              super.afterShow();
              selectionListener.initialSet(getList().getSelectedValue());
            }
          };
          DebuggerUIUtil.registerExtraHandleShortcuts(popup, SHOW_BREAKPOINT_AD, IdeActions.ACTION_TOGGLE_LINE_BREAKPOINT);

          popup.addListSelectionListener(selectionListener);
          popup.show(relativePoint);
        }
        else {
          XLineBreakpointType.XLineBreakpointVariant variant = variants.get(0);
          addLineBreakpoint(res, breakpointManager, variant, file, line, temporary);
        }
      });
      return res;
    });
  }
@NotNull
  public static Promise<@Nullable XLineBreakpoint> toggleAndReturnLineBreakpoint(@NotNull final Project project,
                                                                                 @NotNull List<? extends XLineBreakpointType> types,
                                                                                 @NotNull final XSourcePosition position,
                                                                                 boolean selectVariantByPositionColumn,
                                                                                 final boolean temporary,
                                                                                 @Nullable final Editor editor,
                                                                                 boolean canRemove)