private static FList<TextRange> prependRange( @NotNull FList<TextRange> ranges, int from, int length) { TextRange head = ranges.getHead(); if (head != null && head.getStartOffset() == from + length) { return ranges.getTail().prepend(new TextRange(from, head.getEndOffset())); } return ranges.prepend(TextRange.from(from, length)); }
public int matchingDegree(@NotNull String name) { FList<TextRange> iterable = matchingFragments(name); if (iterable == null) return Integer.MIN_VALUE; if (iterable.isEmpty()) return 0; final TextRange first = iterable.getHead(); boolean startMatch = first.getStartOffset() == 0; int matchingCase = 0; int p = -1; int integral = 0; // -sum of matching-char-count * hump-index over all matched humps; favors longer // fragments matching earlier words int humpIndex = 1; int nextHumpStart = 0; for (TextRange range : iterable) { for (int i = range.getStartOffset(); i < range.getEndOffset(); i++) { boolean isHumpStart = false; while (nextHumpStart <= i) { if (nextHumpStart == i) { isHumpStart = true; } nextHumpStart = NameUtil.nextWord(name, nextHumpStart); if (first != range) { humpIndex++; } } integral -= humpIndex; char c = name.charAt(i); p = StringUtil.indexOf(myPattern, c, p + 1, myPattern.length, false); if (p < 0) { break; } if (c == myPattern[p]) { if (isUpperCase[p]) matchingCase += 50; // strongly prefer user's uppercase matching uppercase: they made an effort to // press Shift else if (i == 0 && startMatch) matchingCase += 15; // the very first letter case distinguishes classes in Java etc else if (isHumpStart) matchingCase += 1; // if a lowercase matches lowercase hump start, that also means something } else if (isHumpStart) { // disfavor hump starts where pattern letter case doesn't match name case matchingCase -= 20; } } } int startIndex = first.getStartOffset(); boolean afterSeparator = StringUtil.indexOfAny(name, HARD_SEPARATORS, 0, startIndex) >= 0; boolean wordStart = startIndex == 0 || isWordStart(name, startIndex) && !isWordStart(name, startIndex - 1); boolean finalMatch = iterable.get(iterable.size() - 1).getEndOffset() == name.length(); return (wordStart ? 1000 : 0) + integral * 10 + matchingCase * (startMatch ? 10 : 1) + // in start matches, case is more important; in middle matches - fragment length // (integral) (afterSeparator ? 0 : 2) + (finalMatch ? 1 : 0); }