private int getPrevOrNextParameterOffset(boolean isNext) {
    if (!(myHandler instanceof ParameterInfoHandlerWithTabActionSupport)) return -1;
    ParameterInfoHandlerWithTabActionSupport handler =
        (ParameterInfoHandlerWithTabActionSupport) myHandler;

    boolean noDelimiter = handler.getActualParameterDelimiterType() == TokenType.WHITE_SPACE;
    int caretOffset = myEditor.getCaretModel().getOffset();
    int offset =
        noDelimiter
            ? caretOffset
            : CharArrayUtil.shiftBackward(
                    myEditor.getDocument().getCharsSequence(), caretOffset - 1, " \t")
                + 1;
    int lbraceOffset = myLbraceMarker.getStartOffset();
    PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(myEditor.getDocument());
    PsiElement argList =
        lbraceOffset < offset ? findArgumentList(file, offset, lbraceOffset) : null;
    if (argList == null) return -1;

    @SuppressWarnings("unchecked")
    PsiElement[] parameters = handler.getActualParameters(argList);
    int currentParameterIndex =
        noDelimiter
            ? JBIterable.of(parameters).indexOf((o) -> o.getTextRange().containsOffset(offset))
            : ParameterInfoUtils.getCurrentParameterIndex(
                argList.getNode(), offset, handler.getActualParameterDelimiterType());

    int prevOrNextParameterIndex =
        isNext && currentParameterIndex < parameters.length - 1
            ? currentParameterIndex + 1
            : !isNext && currentParameterIndex > 0 ? currentParameterIndex - 1 : -1;
    return prevOrNextParameterIndex != -1
        ? parameters[prevOrNextParameterIndex].getTextRange().getStartOffset()
        : -1;
  }
  @Nullable
  public static <E extends PsiElement> E findArgumentList(
      PsiFile file,
      int offset,
      int lbraceOffset,
      @NotNull ParameterInfoHandlerWithTabActionSupport findArgumentListHelper) {
    if (file == null) return null;

    CharSequence chars = file.getViewProvider().getContents();
    if (offset >= chars.length()) offset = chars.length() - 1;
    int offset1 = CharArrayUtil.shiftBackward(chars, offset, " \t\n\r");
    if (offset1 < 0) return null;
    boolean acceptRparenth = true;
    boolean acceptLparenth = false;
    if (offset1 != offset) {
      offset = offset1;
      acceptRparenth = false;
      acceptLparenth = true;
    }

    PsiElement element = file.findElementAt(offset);
    if (element == null) return null;
    PsiElement parent = element.getParent();

    while (true) {
      if (findArgumentListHelper.getArgumentListClass().isInstance(parent)) {
        TextRange range = parent.getTextRange();
        if (!acceptRparenth) {
          if (offset == range.getEndOffset() - 1) {
            PsiElement[] children = parent.getChildren();
            if (children.length == 0) return null;
            PsiElement last = children[children.length - 1];
            if (last.getNode().getElementType()
                == findArgumentListHelper.getActualParametersRBraceType()) {
              parent = parent.getParent();
              continue;
            }
          }
        }
        if (!acceptLparenth) {
          if (offset == range.getStartOffset()) {
            parent = parent.getParent();
            continue;
          }
        }
        if (lbraceOffset >= 0 && range.getStartOffset() != lbraceOffset) {
          parent = parent.getParent();
          continue;
        }
        break;
      }
      if (parent instanceof PsiFile || parent == null) return null;

      final Set<? extends Class> set = findArgumentListHelper.getArgListStopSearchClasses();
      for (Class aClass : set) {
        if (aClass.isInstance(parent)) return null;
      }

      parent = parent.getParent();
    }

    PsiElement listParent = parent.getParent();
    for (Class c : (Set<Class>) findArgumentListHelper.getArgumentListAllowedParentClasses()) {
      if (c.isInstance(listParent)) return (E) parent;
    }

    return null;
  }