protected @Nullable String computeKey(@NotNull CharSequence text) {
    int currentOffset = text.length();
    int groupCount = 0;
    int bracketCount = 0;
    int textCount = 0;

    while (currentOffset > 0) {
      currentOffset--;
      char c = text.charAt(currentOffset);

      if (c == ']') {
        bracketCount++;
      }
      else if (c == '[') {
        if (bracketCount == 0) {
          currentOffset++;
          break;
        }
        bracketCount--;
      }
      else if (c == '}') {
        textCount++;
      }
      else if (c == '{') {
        if (textCount == 0) {
          currentOffset++;
          break;
        }
        textCount--;
      }
      else if (c == ')') {
        groupCount++;
      }
      else if (c == '(') {
        if (groupCount == 0) {
          currentOffset++;
          break;
        }
        groupCount--;
      }
      else {
        if (bracketCount > 0 || textCount > 0) {
          // respect all characters inside attribute sets or text nodes
          continue;
        }
        if (!isAllowedChar(c)) {
          currentOffset++;
          break;
        }
      }
    }
    return groupCount == 0 && textCount == 0 && bracketCount == 0 && currentOffset < text.length()
           ? text.subSequence(currentOffset, text.length()).toString().replaceFirst("^[*+>^]+", "")
           : null;
  }
protected @Nullable String computeKey(@NotNull CharSequence text)