private @Nullable FList<TextRange> findLongestMatchingPrefix(int patternIndex,
                                                                 int nameIndex,
                                                                 int fragmentLength, int minFragment,
                                                                 @NotNull ErrorState errorState) {
      if (patternIndex + fragmentLength >= patternLength(errorState)) {
        int errors = errorState.countErrors(patternIndex, patternIndex + fragmentLength);
        if (errors == fragmentLength) return null;
        return FList.singleton(new Range(nameIndex, nameIndex + fragmentLength, errors));
      }

      // try to match the remainder of pattern with the remainder of name
      // it may not succeed with the longest matching fragment, then try shorter matches
      for (int i = fragmentLength; i >= minFragment || isWildcard(patternIndex + i); i--) {
        ErrorState derivedErrorState = errorState.deriveFrom(patternIndex + i);
        FList<TextRange> ranges = isWildcard(patternIndex + i) ?
                              matchWildcards(patternIndex + i, nameIndex + i, derivedErrorState) :
                              matchSkippingWords(patternIndex + i, nameIndex + i, false, derivedErrorState);
        if (ranges != null) {
          int errors = errorState.countErrors(patternIndex, patternIndex + i);
          if (errors == i) return null;
          return prependRange(ranges, new Range(nameIndex, nameIndex + i, errors));
        }
      }
      return null;
    }
private @Nullable FList<TextRange> findLongestMatchingPrefix(int patternIndex,
                                                                 int nameIndex,
                                                                 int fragmentLength, int minFragment,
                                                                 @NotNull ErrorState errorState)