@Override
  public int calculateWrapPosition(@NotNull Document document,
                                   @Nullable Project project,
                                   int startOffset,
                                   int endOffset,
                                   int maxPreferredOffset,
                                   boolean allowToBeyondMaxPreferredOffset,
                                   boolean isSoftWrap)
  {
    if (endOffset <= startOffset) {
      return endOffset;
    }

    myOffset2weight.clear();
    myOffset2weight.anchor = startOffset;
    CharSequence text = document.getCharsSequence();

    // Normalization.
    int maxPreferredOffsetToUse = maxPreferredOffset >= endOffset ? endOffset - 1 : maxPreferredOffset;
    maxPreferredOffsetToUse = Math.max(maxPreferredOffsetToUse, startOffset);

    // Try to find out wrap position before preferred offset.
    for (int i = Math.min(maxPreferredOffsetToUse, text.length() - 1); i > startOffset; i--) {
      char c = text.charAt(i);
      if (c == '\n') {
        return i + 1;
      }

      if (!canUseOffset(document, i, isSoftWrap)) {
        continue;
      }

      Rule rule = myRules.get(c);
      if (rule != null) {
        if (rule.condition == WrapCondition.BOTH || rule.condition == WrapCondition.AFTER) {
          int target = i+1;
          if (rule.symbol != ' ') {
            while(target < maxPreferredOffsetToUse && text.charAt(target) == ' ') {
              target++;
            }
          }
          if (target <= maxPreferredOffsetToUse) {
            myOffset2weight.store(target, rule.weight);
          }
        }

        if (rule.condition == WrapCondition.BOTH || rule.condition == WrapCondition.BEFORE) {
          myOffset2weight.store(i, rule.weight);
        }
        continue;
      }

      // Don't wrap on a non-id symbol followed by non-id symbol, e.g. don't wrap between two pluses at i++.
      // Also don't wrap before non-id symbol preceded by a space - wrap on space instead;
      if (!isIdSymbol(c) && i > startOffset + 1 && isIdSymbol(text.charAt(i - 1)) && !myRules.containsKey(text.charAt(i - 1))) {
        myOffset2weight.store(i, NON_ID_WEIGHT);
      }
    }

    int result = chooseOffset();
    if (result > 0) {
      return result;
    }

    if (!allowToBeyondMaxPreferredOffset) {
      return -1;
    }

    // Try to find target offset that is beyond preferred offset.
    // Note that we don't consider symbol weights here and just break on the first appropriate position.
    for (int i = Math.min(maxPreferredOffsetToUse + 1, text.length() - 1); i < endOffset; i++) {
      char c = text.charAt(i);
      if (c == '\n') {
        return i + 1;
      }

      if (!canUseOffset(document, i, isSoftWrap)) {
        continue;
      }

      Rule rule = myRules.get(c);
      if (rule != null) {
        switch (rule.condition) {
          case BOTH, BEFORE -> {
            return i;
          }
          case AFTER -> {
            if (i < endOffset - 1) return i + 1;
          }
        }
      }

      // Don't wrap on a non-id symbol followed by non-id symbol, e.g. don't wrap between two pluses at i++;
      if (!isIdSymbol(c) && i < endOffset - 1 && isIdSymbol(text.charAt(i + 1))) {
        return i;
      }
    }

    return -1;
  }
@Override
  public int calculateWrapPosition(@NotNull Document document,
                                   @Nullable Project project,
                                   int startOffset,
                                   int endOffset,
                                   int maxPreferredOffset,
                                   boolean allowToBeyondMaxPreferredOffset,
                                   boolean isSoftWrap)