/**
   * After a wildcard (* or space), search for the first non-wildcard pattern character in the name
   * starting from nameIndex and try to {@link #matchFragment(String, int, int,
   * com.intellij.psi.codeStyle.MinusculeMatcher.MatchingState)} for it.
   */
  @Nullable
  private FList<TextRange> matchWildcards(
      @NotNull String name, int patternIndex, int nameIndex, MatchingState matchingState) {
    if (nameIndex < 0) {
      return null;
    }
    if (!isWildcard(patternIndex)) {
      if (patternIndex == myPattern.length) {
        return FList.emptyList();
      }
      return matchFragment(name, patternIndex, nameIndex, matchingState);
    }

    do {
      patternIndex++;
    } while (isWildcard(patternIndex));

    if (patternIndex == myPattern.length) {
      boolean space = isPatternChar(patternIndex - 1, ' ');
      // the trailing space should match if the pattern ends with the last word part, or only its
      // first hump character
      if (space
          && nameIndex != name.length()
          && (patternIndex < 2 || !NameUtil.isWordStart(myPattern[patternIndex - 2]))) {
        int spaceIndex = name.indexOf(' ', nameIndex);
        if (spaceIndex >= 0) {
          return FList.<TextRange>emptyList().prepend(TextRange.from(spaceIndex, 1));
        }
        return null;
      }
      return FList.emptyList();
    }

    FList<TextRange> ranges = matchFragment(name, patternIndex, nameIndex, matchingState);
    if (ranges != null) {
      return ranges;
    }

    return matchSkippingWords(name, patternIndex, nameIndex, true, matchingState);
  }
예제 #2
0
 public static boolean processParents(
     @NotNull Artifact artifact,
     @NotNull PackagingElementResolvingContext context,
     @NotNull ParentElementProcessor processor,
     int maxLevel) {
   return processParents(
       artifact,
       context,
       processor,
       FList.<Pair<Artifact, CompositePackagingElement<?>>>emptyList(),
       maxLevel,
       new HashSet<Artifact>());
 }
  /**
   * Attempts to match an alphanumeric sequence of pattern (starting at patternIndex) to some
   * continuous substring of name, starting from nameIndex.
   */
  private FList<TextRange> doMatchFragments(
      String name, int patternIndex, int nameIndex, MatchingState matchingState) {
    if (!isFirstCharMatching(name, nameIndex, patternIndex)) {
      return null;
    }

    // middle matches have to be at least of length 3, to prevent too many irrelevant matches
    int minFragment =
        isPatternChar(patternIndex - 1, '*')
                && !isWildcard(patternIndex + 1)
                && Character.isLetterOrDigit(name.charAt(nameIndex))
                && !isWordStart(name, nameIndex)
            ? 3
            : 1;
    int i = 1;
    boolean ignoreCase = myOptions != NameUtil.MatchingCaseSensitivity.ALL;
    while (nameIndex + i < name.length()
        && patternIndex + i < myPattern.length
        && charEquals(
            myPattern[patternIndex + i],
            patternIndex + i,
            name.charAt(nameIndex + i),
            ignoreCase)) {
      if (isUpperCase[patternIndex + i] && myHasHumps) {
        if (i < minFragment) {
          return null;
        }
        // when an uppercase pattern letter matches lowercase name letter, try to find an uppercase
        // (better) match further in the name
        if (myPattern[patternIndex + i] != name.charAt(nameIndex + i)) {
          int nextWordStart = indexOfWordStart(name, patternIndex + i, nameIndex + i);
          FList<TextRange> ranges =
              matchWildcards(name, patternIndex + i, nextWordStart, matchingState);
          if (ranges != null) {
            return prependRange(ranges, nameIndex, i);
          }
          // at least three consecutive uppercase letters shouldn't match lowercase
          if (i > 1 && isUpperCase[patternIndex + i - 1] && isUpperCase[patternIndex + i - 2]) {
            // but if there's a lowercase after them, it can match (in case shift was released a bit
            // later)
            if (nameIndex + i + 1 == name.length()
                || patternIndex + i + 1 < myPattern.length && !isLowerCase[patternIndex + i + 1]) {
              return null;
            }
          }
        }
      }
      i++;
    }

    // we've found the longest fragment matching pattern and name

    if (patternIndex + i >= myPattern.length) {
      return FList.<TextRange>emptyList().prepend(TextRange.from(nameIndex, i));
    }

    // 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
    while (i >= minFragment || isWildcard(patternIndex + i)) {
      FList<TextRange> ranges =
          isWildcard(patternIndex + i)
              ? matchWildcards(name, patternIndex + i, nameIndex + i, matchingState)
              : matchSkippingWords(name, patternIndex + i, nameIndex + i, false, matchingState);
      if (ranges != null) {
        return prependRange(ranges, nameIndex, i);
      }
      i--;
    }
    return null;
  }