file structure wants uppercase after asterisk to be really upper

This commit is contained in:
peter
2012-07-06 17:49:19 +02:00
parent 4c576f2e8a
commit 6812d3f43b
2 changed files with 785 additions and 785 deletions
@@ -1,461 +1,461 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* @author max
*/
package com.intellij.psi.util;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.codeStyle.MinusculeMatcher;
import com.intellij.psi.codeStyle.NameUtil;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.testFramework.UsefulTestCase;
import com.intellij.util.ThrowableRunnable;
import com.intellij.util.containers.CollectionFactory;
import com.intellij.util.text.Matcher;
import org.jetbrains.annotations.NonNls;
import java.util.ArrayList;
import java.util.List;
/**
* @author peter
* @author Konstantin Bulenkov
*/
public class NameUtilTest extends UsefulTestCase {
public void testSimpleCases() throws Exception {
assertMatches("N", "NameUtilTest");
assertMatches("NU", "NameUtilTest");
assertMatches("NUT", "NameUtilTest");
assertMatches("NaUT", "NameUtilTest");
assertDoesntMatch("NeUT", "NameUtilTest");
assertDoesntMatch("NaUTa", "NameUtilTest");
assertMatches("NaUtT", "NameUtilTest");
assertMatches("NaUtT", "NameUtilTest");
assertMatches("NaUtTe", "NameUtilTest");
assertMatches("AACl", "AAClass");
assertMatches("ZZZ", "ZZZZZZZZZZ");
}
public void testSimpleCasesWithFirstLowercased() throws Exception {
assertMatches("N", "nameUtilTest");
assertDoesntMatch("N", "anameUtilTest");
assertMatches("NU", "nameUtilTest");
assertDoesntMatch("NU", "anameUtilTest");
assertMatches("NUT", "nameUtilTest");
assertMatches("NaUT", "nameUtilTest");
assertDoesntMatch("NeUT", "nameUtilTest");
assertDoesntMatch("NaUTa", "nameUtilTest");
assertMatches("NaUtT", "nameUtilTest");
assertMatches("NaUtT", "nameUtilTest");
assertMatches("NaUtTe", "nameUtilTest");
}
public void testSpaceDelimiters() throws Exception {
assertMatches("Na Ut Te", "name util test");
assertMatches("Na Ut Te", "name Util Test");
assertDoesntMatch("Na Ut Ta", "name Util Test");
assertMatches("na ut te", "name util test");
assertMatches("na ut", "name_util_test");
assertMatches("na te", "name_util_test");
assertDoesntMatch("na ti", "name_util_test");
}
public void testXMLCompletion() throws Exception {
assertDoesntMatch("N_T", "NameUtilTest");
assertDoesntMatch("ORGS_ACC", "ORGS_POSITION_ACCOUNTABILITY");
assertDoesntMatch("ORGS-ACC", "ORGS-POSITION_ACCOUNTABILITY");
assertDoesntMatch("ORGS.ACC", "ORGS.POSITION_ACCOUNTABILITY");
}
public void testStarFalsePositive() throws Exception {
assertDoesntMatch("ar*l*p", "AbstractResponseHandler");
}
public void testUnderscoreStyle() throws Exception {
assertMatches("N_U_T", "NAME_UTIL_TEST");
assertMatches("NUT", "NAME_UTIL_TEST");
assertDoesntMatch("NUT", "NameutilTest");
}
public void testAllUppercase() {
assertMatches("NOS", "NetOutputStream");
}
public void testCommonFileNameConventions() throws Exception {
// See IDEADEV-12310
assertMatches("BLWN", "base_layout_without_navigation.xhtml");
assertMatches("BLWN", "base-layout-without-navigation.xhtml");
assertMatches("FC", "faces-config.xml");
assertMatches("ARS", "activity_report_summary.jsp");
assertMatches("AD", "arrow_down.gif");
assertMatches("VL", "vehicle-listings.css");
assertMatches("ARS.j", "activity_report_summary.jsp");
assertDoesntMatch("ARS.j", "activity_report_summary.xml");
assertDoesntMatch("ARS.j", "activity_report_summary_justsometingwrong.xml");
assertDoesntMatch("foo.goo", "foo.bar.goo");
}
public void testSpaceForAnyWordsInBetween() {
assertMatches("fo bar", "fooBar");
assertMatches("foo bar", "fooBar");
assertMatches("foo bar", "fooGooBar");
assertMatches("foo bar", "fooGoo bar");
assertDoesntMatch(" b", "fbi");
assertDoesntMatch(" for", "performAction");
assertTrue(caseInsensitiveMatcher(" us").matches("getUsage"));
assertTrue(caseInsensitiveMatcher(" us").matches("getMyUsage"));
}
private static Matcher caseInsensitiveMatcher(String pattern) {
return NameUtil.buildMatcher(pattern, NameUtil.MatchingCaseSensitivity.NONE);
}
public void testStartDot() {
assertMatches("A*.html", "A.html");
assertMatches("A*.html", "Abc.html");
assertMatches("A*.html", "after.html");
assertDoesntMatch("A*.html", "10_after.html");
}
public void testIDEADEV15503() throws Exception {
assertMatches("AR.jsp", "add_relationship.jsp");
assertMatches("AR.jsp", "advanced_rule.jsp");
assertMatches("AR.jsp", "alarm_reduction.jsp");
assertMatches("AR.jsp", "audiot_report.jsp");
assertMatches("AR.jsp", "audiot_r.jsp");
assertMatches("AR.jsp", "alarm_rule_action.jsp");
assertMatches("AR.jsp", "alarm_rule_admin.jsp");
assertMatches("AR.jsp", "alarm_rule_administration.jsp");
assertMatches("AR.jsp", "alarm_rule_controller.jsp");
assertMatches("AR.jsp", "alarm_rule_frame.jsp");
assertMatches("AR.jsp", "alarm_rule_severity.jsp");
assertMatches("AR.jsp", "AddRelationship.jsp");
assertMatches("AR.jsp", "AdvancedRule.jsp");
assertMatches("AR.jsp", "AlarmReduction.jsp");
assertMatches("AR.jsp", "AudiotReport.jsp");
assertMatches("AR.jsp", "AudiotR.jsp");
assertMatches("AR.jsp", "AlarmRuleAction.jsp");
assertMatches("AR.jsp", "AlarmRuleAdmin.jsp");
assertMatches("AR.jsp", "AlarmRuleAdministration.jsp");
assertMatches("AR.jsp", "AlarmRuleController.jsp");
assertMatches("AR.jsp", "AlarmRuleFrame.jsp");
assertMatches("AR.jsp", "AlarmRuleSeverity.jsp");
}
public void testSkipDot() {
assertMatches("ja", "jquery.autocomplete.js");
assertMatches("ja.js", "jquery.autocomplete.js");
assertDoesntMatch("jajs", "jquery.autocomplete.js");
assertDoesntMatch("j.ajs", "jquery.autocomplete.js");
}
public void testNoExtension() {
assertMatches("#.p", "#.php");
assertMatches("#", "#.php");
assertMatches("a", "a.php");
}
public void testIgnoreCaseWhenCompleteMatch() {
assertMatches("comboBox", "combobox");
assertMatches("combobox", "comboBox");
}
public void testStartsWithDot() throws Exception {
assertMatches(".foo", ".foo");
}
public void testProperDotEscaping() throws Exception {
assertMatches("*inspection*.pro", "InspectionsBundle.properties");
assertDoesntMatch("*inspection*.pro", "InspectionsInProgress.png");
}
public void testIgnoreLeadingUnderscore() throws Exception {
assertMatches("form", "_form.html.erb");
assertMatches("_form", "_form.html.erb");
assertMatches("_form", "__form");
assertFalse(NameUtil.buildMatcher("_form", 1, true, true, false).matches("__form"));
}
public void testLowerCaseWords() throws Exception {
assertTrue(matches("uct", "unit_controller_test"));
assertTrue(matches("unictest", "unit_controller_test"));
assertTrue(matches("uc", "unit_controller_test"));
assertFalse(matches("nc", "unit_controller_test"));
assertFalse(matches("utc", "unit_controller_test"));
}
public void testObjectiveCCases() throws Exception {
assertMatches("text:sh", "textField:shouldChangeCharactersInRange:replacementString:");
assertMatches("abc", "aaa:bbb:ccc");
assertMatches("textField:sh", "textField:shouldChangeCharactersInRange:replacementString:");
assertMatches("text*:sh", "textField:shouldChangeCharactersInRange:replacementString:");
}
public void testMiddleMatching() {
assertTrue(caseInsensitiveMatcher("*OLD").matches("folder"));
assertTrue(caseInsensitiveMatcher("*old").matches("folder"));
assertMatches("SWU*H*7", "SWUpgradeHdlrFSPR7Test");
assertMatches("SWU*H*R", "SWUpgradeHdlrFSPR7Test");
assertMatches("SWU*H*R", "SWUPGRADEHDLRFSPR7TEST");
assertMatches("*git", "GitBlaBla");
assertMatches("*Git", "GitBlaBla");
assertMatches("*git", "BlaGitBla");
assertMatches("*Git", "BlaGitBla");
assertFalse(firstLetterMatcher("*Git").matches("BlagitBla"));
assertMatches("*git", "BlagitBla");
assertMatches("*Git*", "AtpGenerationItem");
assertMatches("Collec*Util*", "CollectionUtils");
assertMatches("Collec*Util*", "CollectionUtilsTest");
assertTrue(caseInsensitiveMatcher("*us").matches("usage"));
assertTrue(caseInsensitiveMatcher(" us").matches("usage"));
assertTrue(caseInsensitiveMatcher(" fo. ba").matches("getFoo.getBar"));
assertMatches(" File. sepa", "File.separator");
assertMatches(" File. sepa", "File._separator");
assertMatches(" File. _sepa", "File._separator");
assertMatches(" _fo", "_foo");
}
public void testMiddleMatchingFirstLetterSensitive() {
assertTrue(firstLetterMatcher(" cl").matches("getClass"));
assertTrue(firstLetterMatcher(" EUC-").matches("x-EUC-TW"));
assertTrue(firstLetterMatcher(" a").matches("aaa"));
assertFalse(firstLetterMatcher(" a").matches("Aaa"));
assertFalse(firstLetterMatcher(" a").matches("Aaa"));
assertFalse(firstLetterMatcher(" _bl").matches("_top"));
}
private static Matcher firstLetterMatcher(String pattern) {
return NameUtil.buildMatcher(pattern, NameUtil.MatchingCaseSensitivity.FIRST_LETTER);
}
public void testSpaceInCompletionPrefix() throws Exception {
assertTrue(caseInsensitiveMatcher("create ").matches("create module"));
}
public void testLong() throws Exception {
assertTrue(matches("Product.findByDateAndNameGreaterThanEqualsAndQualityGreaterThanEqual", "Product.findByDateAndNameGreaterThanEqualsAndQualityGreaterThanEqualsIntellijIdeaRulezzz"));
}
private static void assertMatches(@NonNls String pattern, @NonNls String name) {
assertTrue(matches(pattern, name));
}
private static void assertDoesntMatch(@NonNls String pattern, @NonNls String name) {
assertFalse(matches(pattern, name));
}
private static boolean matches(@NonNls final String pattern, @NonNls final String name) {
return caseInsensitiveMatcher(pattern).matches(name);
}
public void testLowerCaseHumps() {
assertMatches("foo", "foo");
assertDoesntMatch("foo", "fxoo");
assertMatches("foo", "fOo");
assertMatches("foo", "fxOo");
assertDoesntMatch("foo", "fXOo");
assertMatches("fOo", "foo");
assertMatches("fOo", "FaOaOaXXXX");
assertMatches("ncdfoe", "NoClassDefFoundException");
assertMatches("fob", "FOO_BAR");
assertMatches("fo_b", "FOO_BAR");
assertMatches("fob", "FOO BAR");
assertMatches("fo b", "FOO BAR");
assertMatches("AACl", "AAClass");
assertMatches("ZZZ", "ZZZZZZZZZZ");
assertMatches("em", "emptyList");
assertMatches("bui", "BuildConfig.groovy");
assertMatches("buico", "BuildConfig.groovy");
assertMatches("buico.gr", "BuildConfig.groovy");
assertMatches("bui.gr", "BuildConfig.groovy");
assertMatches("*fz", "azzzfzzz");
assertMatches("WebLogic", "Weblogic");
assertMatches("WebLOgic", "WebLogic");
assertMatches("WEbLogic", "WebLogic");
assertDoesntMatch("WebLogic", "Webologic");
}
public void testFinalSpace() {
assertMatches("GrDebT ", "GroovyDebuggerTest");
assertMatches("grdebT ", "GroovyDebuggerTest");
assertDoesntMatch("grdebt ", "GroovyDebuggerTest");
assertMatches("Foo ", "Foo");
assertDoesntMatch("Foo ", "FooBar");
assertDoesntMatch("Foo ", "Foox");
assertDoesntMatch("Collections ", "CollectionSplitter");
assertMatches("CollectionS ", "CollectionSplitter");
}
public void testDigits() {
assertMatches("foba4", "FooBar4");
assertMatches("foba", "Foo4Bar");
assertMatches("*TEST-* ", "TEST-001");
assertMatches("*TEST-0* ", "TEST-001");
}
public void testSpecialSymbols() {
assertMatches("a@b", "a@bc");
assertMatches("a/text", "a/Text");
assertDoesntMatch("a/text", "a/bbbText");
}
public void testMinusculeFirstLetter() {
assertTrue(new MinusculeMatcher("WebLogic", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matches("WebLogic"));
assertFalse(new MinusculeMatcher("webLogic", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matches("WebLogic"));
assertTrue(new MinusculeMatcher("cL", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matches("class"));
assertTrue(new MinusculeMatcher("CL", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matches("Class"));
assertFalse(new MinusculeMatcher("abc", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matches("_abc"));
}
public void testMinusculeAllImportant() {
assertTrue(new MinusculeMatcher("WebLogic", NameUtil.MatchingCaseSensitivity.ALL).matches("WebLogic"));
assertFalse(new MinusculeMatcher("webLogic", NameUtil.MatchingCaseSensitivity.ALL).matches("weblogic"));
assertFalse(new MinusculeMatcher("FOO", NameUtil.MatchingCaseSensitivity.ALL).matches("foo"));
assertFalse(new MinusculeMatcher("foo", NameUtil.MatchingCaseSensitivity.ALL).matches("fOO"));
assertFalse(new MinusculeMatcher("Wl", NameUtil.MatchingCaseSensitivity.ALL).matches("WebLogic"));
assertTrue(new MinusculeMatcher("WL", NameUtil.MatchingCaseSensitivity.ALL).matches("WebLogic"));
assertFalse(new MinusculeMatcher("WL", NameUtil.MatchingCaseSensitivity.ALL).matches("Weblogic"));
assertFalse(new MinusculeMatcher("WL", NameUtil.MatchingCaseSensitivity.ALL).matches("weblogic"));
assertFalse(new MinusculeMatcher("webLogic", NameUtil.MatchingCaseSensitivity.ALL).matches("WebLogic"));
assertFalse(new MinusculeMatcher("Str", NameUtil.MatchingCaseSensitivity.ALL).matches("SomeThingRidiculous"));
}
public void testMatchingFragments() {
@NonNls String sample = "NoClassDefFoundException";
// 0 2 7 10 15 21
assertOrderedEquals(new MinusculeMatcher("ncldfou*ion", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample),
TextRange.from(0, 1), TextRange.from(2, 2), TextRange.from(7, 1), TextRange.from(10, 3), TextRange.from(21, 3));
sample = "doGet(HttpServletRequest, HttpServletResponse):void";
// 0 22
assertOrderedEquals(new MinusculeMatcher("d*st", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample),
TextRange.from(0, 1), TextRange.from(22, 2));
assertOrderedEquals(new MinusculeMatcher("doge*st", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample),
TextRange.from(0, 4), TextRange.from(22, 2));
sample = "_test";
assertOrderedEquals(new MinusculeMatcher("_", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample),
TextRange.from(0, 1));
assertOrderedEquals(new MinusculeMatcher("_t", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample),
TextRange.from(0, 2));
}
public void testMatchingFragmentsSorted() {
@NonNls String sample = "SWUPGRADEHDLRFSPR7TEST";
// 0 9 12
assertOrderedEquals(new MinusculeMatcher("SWU*H*R", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample),
TextRange.from(0, 3), TextRange.from(9, 1), TextRange.from(12, 1));
}
public void testPreferCapsMatching() {
String sample = "getCurrentUser";
// 0 4 10
assertOrderedEquals(new MinusculeMatcher("getCU", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample),
TextRange.from(0, 4), TextRange.from(10, 1));
}
public void testMatchingDegree() {
assertPreference("jscote", "JsfCompletionTest", "JSCompletionTest", NameUtil.MatchingCaseSensitivity.NONE);
assertPreference("OCO", "OneCoolObject", "OCObject");
assertPreference("MUp", "MavenUmlProvider", "MarkUp");
assertPreference("MUP", "MarkUp", "MavenUmlProvider");
assertPreference("CertificateExce", "CertificateEncodingException", "CertificateException");
assertPreference("boo", "Boolean", "boolean", NameUtil.MatchingCaseSensitivity.NONE);
assertPreference("Boo", "boolean", "Boolean", NameUtil.MatchingCaseSensitivity.NONE);
assertPreference("getCU", "getCurrentSomething", "getCurrentUser");
assertPreference("cL", "class", "coreLoader");
assertPreference("cL", "class", "classLoader");
}
public void testPreferStartMatchToMiddleMatch() {
assertPreference(" fb", "FooBar", "_fooBar", NameUtil.MatchingCaseSensitivity.NONE);
assertPreference("*foo", "barFoo", "foobar");
assertPreference("*f", "barfoo", "barFoo");
assertPreference("*f", "barfoo", "foo");
assertPreference("*f", "asdf", "Foo", NameUtil.MatchingCaseSensitivity.NONE);
assertPreference(" sto", "ArrayStoreException", "StackOverflowError", NameUtil.MatchingCaseSensitivity.NONE);
assertPreference(" EUC-", "x-EUC-TW", "EUC-JP");
assertPreference(" boo", "Boolean", "boolean", NameUtil.MatchingCaseSensitivity.NONE);
assertPreference(" Boo", "boolean", "Boolean", NameUtil.MatchingCaseSensitivity.NONE);
}
public void testPreferWordBoundaryMatch() {
assertPreference("*les", "configureByFiles", "getLookupElementStrings", NameUtil.MatchingCaseSensitivity.FIRST_LETTER);
assertPreference("*les", "configureByFiles", "getLookupElementStrings", NameUtil.MatchingCaseSensitivity.NONE);
}
public void testPreferEarlyMatching() {
assertPreference(" path", "getAbsolutePath", "findPath");
}
public void testMeaningfulMatchingDegree() {
assertTrue(new MinusculeMatcher(" EUC-", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matchingDegree("x-EUC-TW") > Integer.MIN_VALUE);
}
private static void assertPreference(@NonNls String pattern,
@NonNls String less,
@NonNls String more) {
assertPreference(pattern, less, more, NameUtil.MatchingCaseSensitivity.FIRST_LETTER);
}
private static void assertPreference(@NonNls String pattern,
@NonNls String less,
@NonNls String more,
NameUtil.MatchingCaseSensitivity sensitivity) {
MinusculeMatcher matcher = new MinusculeMatcher(pattern, sensitivity);
int iLess = matcher.matchingDegree(less);
int iMore = matcher.matchingDegree(more);
assertTrue(iLess + ">=" + iMore + "; " + less + ">=" + more, iLess < iMore);
}
public void testPerformance() {
@NonNls final String longName = "ThisIsAQuiteLongNameWithParentheses().Dots.-Minuses-_UNDERSCORES_digits239:colons:/slashes\\AndOfCourseManyLetters";
final List<MinusculeMatcher> matching = new ArrayList<MinusculeMatcher>();
final List<MinusculeMatcher> nonMatching = new ArrayList<MinusculeMatcher>();
for (String s : CollectionFactory.ar("*", "*i", "*a", "*u", "T", "ti", longName, longName.substring(0, 20))) {
matching.add(new MinusculeMatcher(s, NameUtil.MatchingCaseSensitivity.NONE));
}
for (String s : CollectionFactory.ar("A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "ta")) {
nonMatching.add(new MinusculeMatcher(s, NameUtil.MatchingCaseSensitivity.NONE));
}
PlatformTestUtil.startPerformanceTest("Matcher is slow", 1700, new ThrowableRunnable() {
@Override
public void run() {
for (int i = 0; i < 100000; i++) {
for (MinusculeMatcher matcher : matching) {
assertTrue(matcher.matches(longName));
}
for (MinusculeMatcher matcher : nonMatching) {
assertFalse(matcher.matches(longName));
}
}
}
}).cpuBound().assertTiming();
}
}
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* @author max
*/
package com.intellij.psi.util;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.codeStyle.MinusculeMatcher;
import com.intellij.psi.codeStyle.NameUtil;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.testFramework.UsefulTestCase;
import com.intellij.util.ThrowableRunnable;
import com.intellij.util.containers.CollectionFactory;
import com.intellij.util.text.Matcher;
import org.jetbrains.annotations.NonNls;
import java.util.ArrayList;
import java.util.List;
/**
* @author peter
* @author Konstantin Bulenkov
*/
public class NameUtilTest extends UsefulTestCase {
public void testSimpleCases() throws Exception {
assertMatches("N", "NameUtilTest");
assertMatches("NU", "NameUtilTest");
assertMatches("NUT", "NameUtilTest");
assertMatches("NaUT", "NameUtilTest");
assertDoesntMatch("NeUT", "NameUtilTest");
assertDoesntMatch("NaUTa", "NameUtilTest");
assertMatches("NaUtT", "NameUtilTest");
assertMatches("NaUtT", "NameUtilTest");
assertMatches("NaUtTe", "NameUtilTest");
assertMatches("AACl", "AAClass");
assertMatches("ZZZ", "ZZZZZZZZZZ");
}
public void testSimpleCasesWithFirstLowercased() throws Exception {
assertMatches("N", "nameUtilTest");
assertDoesntMatch("N", "anameUtilTest");
assertMatches("NU", "nameUtilTest");
assertDoesntMatch("NU", "anameUtilTest");
assertMatches("NUT", "nameUtilTest");
assertMatches("NaUT", "nameUtilTest");
assertDoesntMatch("NeUT", "nameUtilTest");
assertDoesntMatch("NaUTa", "nameUtilTest");
assertMatches("NaUtT", "nameUtilTest");
assertMatches("NaUtT", "nameUtilTest");
assertMatches("NaUtTe", "nameUtilTest");
}
public void testSpaceDelimiters() throws Exception {
assertMatches("Na Ut Te", "name util test");
assertMatches("Na Ut Te", "name Util Test");
assertDoesntMatch("Na Ut Ta", "name Util Test");
assertMatches("na ut te", "name util test");
assertMatches("na ut", "name_util_test");
assertMatches("na te", "name_util_test");
assertDoesntMatch("na ti", "name_util_test");
}
public void testXMLCompletion() throws Exception {
assertDoesntMatch("N_T", "NameUtilTest");
assertDoesntMatch("ORGS_ACC", "ORGS_POSITION_ACCOUNTABILITY");
assertDoesntMatch("ORGS-ACC", "ORGS-POSITION_ACCOUNTABILITY");
assertDoesntMatch("ORGS.ACC", "ORGS.POSITION_ACCOUNTABILITY");
}
public void testStarFalsePositive() throws Exception {
assertDoesntMatch("ar*l*p", "AbstractResponseHandler");
}
public void testUnderscoreStyle() throws Exception {
assertMatches("N_U_T", "NAME_UTIL_TEST");
assertMatches("NUT", "NAME_UTIL_TEST");
assertDoesntMatch("NUT", "NameutilTest");
}
public void testAllUppercase() {
assertMatches("NOS", "NetOutputStream");
}
public void testCommonFileNameConventions() throws Exception {
// See IDEADEV-12310
assertMatches("BLWN", "base_layout_without_navigation.xhtml");
assertMatches("BLWN", "base-layout-without-navigation.xhtml");
assertMatches("FC", "faces-config.xml");
assertMatches("ARS", "activity_report_summary.jsp");
assertMatches("AD", "arrow_down.gif");
assertMatches("VL", "vehicle-listings.css");
assertMatches("ARS.j", "activity_report_summary.jsp");
assertDoesntMatch("ARS.j", "activity_report_summary.xml");
assertDoesntMatch("ARS.j", "activity_report_summary_justsometingwrong.xml");
assertDoesntMatch("foo.goo", "foo.bar.goo");
}
public void testSpaceForAnyWordsInBetween() {
assertMatches("fo bar", "fooBar");
assertMatches("foo bar", "fooBar");
assertMatches("foo bar", "fooGooBar");
assertMatches("foo bar", "fooGoo bar");
assertDoesntMatch(" b", "fbi");
assertDoesntMatch(" for", "performAction");
assertTrue(caseInsensitiveMatcher(" us").matches("getUsage"));
assertTrue(caseInsensitiveMatcher(" us").matches("getMyUsage"));
}
private static Matcher caseInsensitiveMatcher(String pattern) {
return NameUtil.buildMatcher(pattern, NameUtil.MatchingCaseSensitivity.NONE);
}
public void testStartDot() {
assertMatches("A*.html", "A.html");
assertMatches("A*.html", "Abc.html");
assertMatches("A*.html", "after.html");
assertDoesntMatch("A*.html", "10_after.html");
}
public void testIDEADEV15503() throws Exception {
assertMatches("AR.jsp", "add_relationship.jsp");
assertMatches("AR.jsp", "advanced_rule.jsp");
assertMatches("AR.jsp", "alarm_reduction.jsp");
assertMatches("AR.jsp", "audiot_report.jsp");
assertMatches("AR.jsp", "audiot_r.jsp");
assertMatches("AR.jsp", "alarm_rule_action.jsp");
assertMatches("AR.jsp", "alarm_rule_admin.jsp");
assertMatches("AR.jsp", "alarm_rule_administration.jsp");
assertMatches("AR.jsp", "alarm_rule_controller.jsp");
assertMatches("AR.jsp", "alarm_rule_frame.jsp");
assertMatches("AR.jsp", "alarm_rule_severity.jsp");
assertMatches("AR.jsp", "AddRelationship.jsp");
assertMatches("AR.jsp", "AdvancedRule.jsp");
assertMatches("AR.jsp", "AlarmReduction.jsp");
assertMatches("AR.jsp", "AudiotReport.jsp");
assertMatches("AR.jsp", "AudiotR.jsp");
assertMatches("AR.jsp", "AlarmRuleAction.jsp");
assertMatches("AR.jsp", "AlarmRuleAdmin.jsp");
assertMatches("AR.jsp", "AlarmRuleAdministration.jsp");
assertMatches("AR.jsp", "AlarmRuleController.jsp");
assertMatches("AR.jsp", "AlarmRuleFrame.jsp");
assertMatches("AR.jsp", "AlarmRuleSeverity.jsp");
}
public void testSkipDot() {
assertMatches("ja", "jquery.autocomplete.js");
assertMatches("ja.js", "jquery.autocomplete.js");
assertDoesntMatch("jajs", "jquery.autocomplete.js");
assertDoesntMatch("j.ajs", "jquery.autocomplete.js");
}
public void testNoExtension() {
assertMatches("#.p", "#.php");
assertMatches("#", "#.php");
assertMatches("a", "a.php");
}
public void testIgnoreCaseWhenCompleteMatch() {
assertMatches("comboBox", "combobox");
assertMatches("combobox", "comboBox");
}
public void testStartsWithDot() throws Exception {
assertMatches(".foo", ".foo");
}
public void testProperDotEscaping() throws Exception {
assertMatches("*inspection*.pro", "InspectionsBundle.properties");
assertDoesntMatch("*inspection*.pro", "InspectionsInProgress.png");
}
public void testIgnoreLeadingUnderscore() throws Exception {
assertMatches("form", "_form.html.erb");
assertMatches("_form", "_form.html.erb");
assertMatches("_form", "__form");
assertFalse(NameUtil.buildMatcher("_form", 1, true, true, false).matches("__form"));
}
public void testLowerCaseWords() throws Exception {
assertTrue(matches("uct", "unit_controller_test"));
assertTrue(matches("unictest", "unit_controller_test"));
assertTrue(matches("uc", "unit_controller_test"));
assertFalse(matches("nc", "unit_controller_test"));
assertFalse(matches("utc", "unit_controller_test"));
}
public void testObjectiveCCases() throws Exception {
assertMatches("text:sh", "textField:shouldChangeCharactersInRange:replacementString:");
assertMatches("abc", "aaa:bbb:ccc");
assertMatches("textField:sh", "textField:shouldChangeCharactersInRange:replacementString:");
assertMatches("text*:sh", "textField:shouldChangeCharactersInRange:replacementString:");
}
public void testMiddleMatching() {
assertTrue(caseInsensitiveMatcher("*old").matches("folder"));
assertMatches("SWU*H*7", "SWUpgradeHdlrFSPR7Test");
assertMatches("SWU*H*R", "SWUpgradeHdlrFSPR7Test");
assertMatches("SWU*H*R", "SWUPGRADEHDLRFSPR7TEST");
assertMatches("*git", "GitBlaBla");
assertMatches("*Git", "GitBlaBla");
assertDoesntMatch("*get*A", "getClass");
assertMatches("*git", "BlaGitBla");
assertMatches("*Git", "BlaGitBla");
assertFalse(firstLetterMatcher("*Git").matches("BlagitBla"));
assertMatches("*git", "BlagitBla");
assertMatches("*Git*", "AtpGenerationItem");
assertMatches("Collec*Util*", "CollectionUtils");
assertMatches("Collec*Util*", "CollectionUtilsTest");
assertTrue(caseInsensitiveMatcher("*us").matches("usage"));
assertTrue(caseInsensitiveMatcher(" us").matches("usage"));
assertTrue(caseInsensitiveMatcher(" fo. ba").matches("getFoo.getBar"));
assertMatches(" File. sepa", "File.separator");
assertMatches(" File. sepa", "File._separator");
assertMatches(" File. _sepa", "File._separator");
assertMatches(" _fo", "_foo");
}
public void testMiddleMatchingFirstLetterSensitive() {
assertTrue(firstLetterMatcher(" cl").matches("getClass"));
assertTrue(firstLetterMatcher(" EUC-").matches("x-EUC-TW"));
assertTrue(firstLetterMatcher(" a").matches("aaa"));
assertFalse(firstLetterMatcher(" a").matches("Aaa"));
assertFalse(firstLetterMatcher(" a").matches("Aaa"));
assertFalse(firstLetterMatcher(" _bl").matches("_top"));
}
private static Matcher firstLetterMatcher(String pattern) {
return NameUtil.buildMatcher(pattern, NameUtil.MatchingCaseSensitivity.FIRST_LETTER);
}
public void testSpaceInCompletionPrefix() throws Exception {
assertTrue(caseInsensitiveMatcher("create ").matches("create module"));
}
public void testLong() throws Exception {
assertTrue(matches("Product.findByDateAndNameGreaterThanEqualsAndQualityGreaterThanEqual", "Product.findByDateAndNameGreaterThanEqualsAndQualityGreaterThanEqualsIntellijIdeaRulezzz"));
}
private static void assertMatches(@NonNls String pattern, @NonNls String name) {
assertTrue(matches(pattern, name));
}
private static void assertDoesntMatch(@NonNls String pattern, @NonNls String name) {
assertFalse(matches(pattern, name));
}
private static boolean matches(@NonNls final String pattern, @NonNls final String name) {
return caseInsensitiveMatcher(pattern).matches(name);
}
public void testLowerCaseHumps() {
assertMatches("foo", "foo");
assertDoesntMatch("foo", "fxoo");
assertMatches("foo", "fOo");
assertMatches("foo", "fxOo");
assertDoesntMatch("foo", "fXOo");
assertMatches("fOo", "foo");
assertMatches("fOo", "FaOaOaXXXX");
assertMatches("ncdfoe", "NoClassDefFoundException");
assertMatches("fob", "FOO_BAR");
assertMatches("fo_b", "FOO_BAR");
assertMatches("fob", "FOO BAR");
assertMatches("fo b", "FOO BAR");
assertMatches("AACl", "AAClass");
assertMatches("ZZZ", "ZZZZZZZZZZ");
assertMatches("em", "emptyList");
assertMatches("bui", "BuildConfig.groovy");
assertMatches("buico", "BuildConfig.groovy");
assertMatches("buico.gr", "BuildConfig.groovy");
assertMatches("bui.gr", "BuildConfig.groovy");
assertMatches("*fz", "azzzfzzz");
assertMatches("WebLogic", "Weblogic");
assertMatches("WebLOgic", "WebLogic");
assertMatches("WEbLogic", "WebLogic");
assertDoesntMatch("WebLogic", "Webologic");
}
public void testFinalSpace() {
assertMatches("GrDebT ", "GroovyDebuggerTest");
assertMatches("grdebT ", "GroovyDebuggerTest");
assertDoesntMatch("grdebt ", "GroovyDebuggerTest");
assertMatches("Foo ", "Foo");
assertDoesntMatch("Foo ", "FooBar");
assertDoesntMatch("Foo ", "Foox");
assertDoesntMatch("Collections ", "CollectionSplitter");
assertMatches("CollectionS ", "CollectionSplitter");
}
public void testDigits() {
assertMatches("foba4", "FooBar4");
assertMatches("foba", "Foo4Bar");
assertMatches("*TEST-* ", "TEST-001");
assertMatches("*TEST-0* ", "TEST-001");
}
public void testSpecialSymbols() {
assertMatches("a@b", "a@bc");
assertMatches("a/text", "a/Text");
assertDoesntMatch("a/text", "a/bbbText");
}
public void testMinusculeFirstLetter() {
assertTrue(new MinusculeMatcher("WebLogic", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matches("WebLogic"));
assertFalse(new MinusculeMatcher("webLogic", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matches("WebLogic"));
assertTrue(new MinusculeMatcher("cL", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matches("class"));
assertTrue(new MinusculeMatcher("CL", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matches("Class"));
assertFalse(new MinusculeMatcher("abc", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matches("_abc"));
}
public void testMinusculeAllImportant() {
assertTrue(new MinusculeMatcher("WebLogic", NameUtil.MatchingCaseSensitivity.ALL).matches("WebLogic"));
assertFalse(new MinusculeMatcher("webLogic", NameUtil.MatchingCaseSensitivity.ALL).matches("weblogic"));
assertFalse(new MinusculeMatcher("FOO", NameUtil.MatchingCaseSensitivity.ALL).matches("foo"));
assertFalse(new MinusculeMatcher("foo", NameUtil.MatchingCaseSensitivity.ALL).matches("fOO"));
assertFalse(new MinusculeMatcher("Wl", NameUtil.MatchingCaseSensitivity.ALL).matches("WebLogic"));
assertTrue(new MinusculeMatcher("WL", NameUtil.MatchingCaseSensitivity.ALL).matches("WebLogic"));
assertFalse(new MinusculeMatcher("WL", NameUtil.MatchingCaseSensitivity.ALL).matches("Weblogic"));
assertFalse(new MinusculeMatcher("WL", NameUtil.MatchingCaseSensitivity.ALL).matches("weblogic"));
assertFalse(new MinusculeMatcher("webLogic", NameUtil.MatchingCaseSensitivity.ALL).matches("WebLogic"));
assertFalse(new MinusculeMatcher("Str", NameUtil.MatchingCaseSensitivity.ALL).matches("SomeThingRidiculous"));
}
public void testMatchingFragments() {
@NonNls String sample = "NoClassDefFoundException";
// 0 2 7 10 15 21
assertOrderedEquals(new MinusculeMatcher("ncldfou*ion", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample),
TextRange.from(0, 1), TextRange.from(2, 2), TextRange.from(7, 1), TextRange.from(10, 3), TextRange.from(21, 3));
sample = "doGet(HttpServletRequest, HttpServletResponse):void";
// 0 22
assertOrderedEquals(new MinusculeMatcher("d*st", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample),
TextRange.from(0, 1), TextRange.from(22, 2));
assertOrderedEquals(new MinusculeMatcher("doge*st", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample),
TextRange.from(0, 4), TextRange.from(22, 2));
sample = "_test";
assertOrderedEquals(new MinusculeMatcher("_", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample),
TextRange.from(0, 1));
assertOrderedEquals(new MinusculeMatcher("_t", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample),
TextRange.from(0, 2));
}
public void testMatchingFragmentsSorted() {
@NonNls String sample = "SWUPGRADEHDLRFSPR7TEST";
// 0 9 12
assertOrderedEquals(new MinusculeMatcher("SWU*H*R", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample),
TextRange.from(0, 3), TextRange.from(9, 1), TextRange.from(12, 1));
}
public void testPreferCapsMatching() {
String sample = "getCurrentUser";
// 0 4 10
assertOrderedEquals(new MinusculeMatcher("getCU", NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(sample),
TextRange.from(0, 4), TextRange.from(10, 1));
}
public void testMatchingDegree() {
assertPreference("jscote", "JsfCompletionTest", "JSCompletionTest", NameUtil.MatchingCaseSensitivity.NONE);
assertPreference("OCO", "OneCoolObject", "OCObject");
assertPreference("MUp", "MavenUmlProvider", "MarkUp");
assertPreference("MUP", "MarkUp", "MavenUmlProvider");
assertPreference("CertificateExce", "CertificateEncodingException", "CertificateException");
assertPreference("boo", "Boolean", "boolean", NameUtil.MatchingCaseSensitivity.NONE);
assertPreference("Boo", "boolean", "Boolean", NameUtil.MatchingCaseSensitivity.NONE);
assertPreference("getCU", "getCurrentSomething", "getCurrentUser");
assertPreference("cL", "class", "coreLoader");
assertPreference("cL", "class", "classLoader");
}
public void testPreferStartMatchToMiddleMatch() {
assertPreference(" fb", "FooBar", "_fooBar", NameUtil.MatchingCaseSensitivity.NONE);
assertPreference("*foo", "barFoo", "foobar");
assertPreference("*f", "barfoo", "barFoo");
assertPreference("*f", "barfoo", "foo");
assertPreference("*f", "asdf", "Foo", NameUtil.MatchingCaseSensitivity.NONE);
assertPreference(" sto", "ArrayStoreException", "StackOverflowError", NameUtil.MatchingCaseSensitivity.NONE);
assertPreference(" EUC-", "x-EUC-TW", "EUC-JP");
assertPreference(" boo", "Boolean", "boolean", NameUtil.MatchingCaseSensitivity.NONE);
assertPreference(" Boo", "boolean", "Boolean", NameUtil.MatchingCaseSensitivity.NONE);
}
public void testPreferWordBoundaryMatch() {
assertPreference("*les", "configureByFiles", "getLookupElementStrings", NameUtil.MatchingCaseSensitivity.FIRST_LETTER);
assertPreference("*les", "configureByFiles", "getLookupElementStrings", NameUtil.MatchingCaseSensitivity.NONE);
}
public void testPreferEarlyMatching() {
assertPreference(" path", "getAbsolutePath", "findPath");
}
public void testMeaningfulMatchingDegree() {
assertTrue(new MinusculeMatcher(" EUC-", NameUtil.MatchingCaseSensitivity.FIRST_LETTER).matchingDegree("x-EUC-TW") > Integer.MIN_VALUE);
}
private static void assertPreference(@NonNls String pattern,
@NonNls String less,
@NonNls String more) {
assertPreference(pattern, less, more, NameUtil.MatchingCaseSensitivity.FIRST_LETTER);
}
private static void assertPreference(@NonNls String pattern,
@NonNls String less,
@NonNls String more,
NameUtil.MatchingCaseSensitivity sensitivity) {
MinusculeMatcher matcher = new MinusculeMatcher(pattern, sensitivity);
int iLess = matcher.matchingDegree(less);
int iMore = matcher.matchingDegree(more);
assertTrue(iLess + ">=" + iMore + "; " + less + ">=" + more, iLess < iMore);
}
public void testPerformance() {
@NonNls final String longName = "ThisIsAQuiteLongNameWithParentheses().Dots.-Minuses-_UNDERSCORES_digits239:colons:/slashes\\AndOfCourseManyLetters";
final List<MinusculeMatcher> matching = new ArrayList<MinusculeMatcher>();
final List<MinusculeMatcher> nonMatching = new ArrayList<MinusculeMatcher>();
for (String s : CollectionFactory.ar("*", "*i", "*a", "*u", "T", "ti", longName, longName.substring(0, 20))) {
matching.add(new MinusculeMatcher(s, NameUtil.MatchingCaseSensitivity.NONE));
}
for (String s : CollectionFactory.ar("A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "ta")) {
nonMatching.add(new MinusculeMatcher(s, NameUtil.MatchingCaseSensitivity.NONE));
}
PlatformTestUtil.startPerformanceTest("Matcher is slow", 1700, new ThrowableRunnable() {
@Override
public void run() {
for (int i = 0; i < 100000; i++) {
for (MinusculeMatcher matcher : matching) {
assertTrue(matcher.matches(longName));
}
for (MinusculeMatcher matcher : nonMatching) {
assertFalse(matcher.matches(longName));
}
}
}
}).cpuBound().assertTiming();
}
}
@@ -1,324 +1,324 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.FList;
import com.intellij.util.text.CharArrayCharSequence;
import com.intellij.util.text.Matcher;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.Iterator;
/**
* @author peter
*/
public class MinusculeMatcher implements Matcher {
private final char[] myPattern;
private final NameUtil.MatchingCaseSensitivity myOptions;
public MinusculeMatcher(String pattern, NameUtil.MatchingCaseSensitivity options) {
myOptions = options;
myPattern = StringUtil.trimEnd(pattern, "* ").replaceAll(":", "\\*:").toCharArray();
}
@Nullable
private FList<TextRange> matchName(String name, int patternIndex, int nameIndex) {
if (patternIndex == myPattern.length) {
return FList.emptyList();
}
if ('*' == myPattern[patternIndex]) {
return skipChars(name, patternIndex, nameIndex, true);
}
if (nameIndex == name.length()) {
return null;
}
if ('.' == myPattern[patternIndex] && name.charAt(nameIndex) != '.') {
return skipChars(name, patternIndex, nameIndex, false);
}
if (' ' == myPattern[patternIndex] && patternIndex != myPattern.length - 1) {
return skipWords(name, patternIndex, nameIndex);
}
if ((patternIndex == 0 || patternIndex == 1 && myPattern[0] == ' ' && nameIndex == 0) &&
myOptions != NameUtil.MatchingCaseSensitivity.NONE && name.charAt(nameIndex) != myPattern[patternIndex]) {
return null;
}
if (NameUtil.isWordSeparator(name.charAt(nameIndex))) {
return skipSeparators(name, patternIndex, nameIndex);
}
if (StringUtil.toLowerCase(name.charAt(nameIndex)) != StringUtil.toLowerCase(myPattern[patternIndex])) {
if (Character.isDigit(name.charAt(nameIndex)) && nameIndex > 0 || (name.charAt(nameIndex) == '.' && name.indexOf('.', nameIndex + 1) > 0)) {
return matchName(name, patternIndex, nameIndex + 1);
}
return null;
}
if (myOptions == NameUtil.MatchingCaseSensitivity.ALL && name.charAt(nameIndex) != myPattern[patternIndex]) {
return null;
}
int nextStart = NameUtil.nextWord(name, nameIndex);
int lastUpper = NameUtil.isWordStart(myPattern[patternIndex]) ? 0 : -1;
int i = 1;
while (true) {
if (patternIndex + i == myPattern.length || i + nameIndex == nextStart) {
break;
}
char p = myPattern[patternIndex + i];
char w = name.charAt(i + nameIndex);
if (lastUpper == i - 1 && NameUtil.isWordStart(p) && myOptions != NameUtil.MatchingCaseSensitivity.ALL) {
if (p == w) {
lastUpper = i;
}
p = StringUtil.toLowerCase(p);
}
if (myOptions != NameUtil.MatchingCaseSensitivity.ALL) {
w = StringUtil.toLowerCase(w);
}
if (w != p) {
break;
}
i++;
}
if (isFinalSpaceMatch(name, patternIndex, nameIndex, nextStart, i)) {
return FList.<TextRange>emptyList().prepend(TextRange.from(nameIndex, i));
}
return matchAfterFragment(name, patternIndex, nameIndex, nextStart, lastUpper, i);
}
private boolean isFinalSpaceMatch(String name, int patternIndex, int nameIndex, int nextStart, int i) {
return nextStart == name.length() &&
patternIndex + i == myPattern.length - 1 &&
' ' == myPattern[patternIndex + i] &&
(i == 1 && NameUtil.isWordStart(myPattern[patternIndex]) || i + nameIndex == name.length());
}
@Nullable
private FList<TextRange> matchAfterFragment(String name, int patternIndex, int nameIndex, int nextStart, int lastUpper, int matchLen) {
boolean star = patternIndex + matchLen < myPattern.length && myPattern[patternIndex + matchLen] == '*';
if (lastUpper >= 0) {
FList<TextRange> ranges = matchName(name, patternIndex + lastUpper + 1, star && matchLen == lastUpper ? nameIndex + lastUpper : nextStart);
if (ranges != null) {
return prependRange(ranges, nameIndex, lastUpper + 1);
}
}
int trial = matchLen;
while (trial > 0) {
FList<TextRange> ranges = matchName(name, patternIndex + trial, nextStart);
if (ranges != null) {
return prependRange(ranges, nameIndex, trial);
}
trial--;
}
FList<TextRange> ranges = matchName(name, patternIndex + matchLen, nameIndex + matchLen);
if (ranges != null) {
return prependRange(ranges, nameIndex, matchLen);
}
return null;
}
private static FList<TextRange> prependRange(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));
}
@Nullable
private FList<TextRange> skipSeparators(String name, int patternIndex, int nameIndex) {
int nextStart = NameUtil.nextWord(name, nameIndex);
assert nextStart - nameIndex == 1 : "'" + name + "'" + nameIndex + " " + nextStart;
char p = myPattern[patternIndex];
if (NameUtil.isWordSeparator(p)) {
if (myOptions != NameUtil.MatchingCaseSensitivity.NONE &&
nameIndex == 0 && name.length() > 1 && patternIndex + 1 < myPattern.length &&
NameUtil.isWordSeparator(name.charAt(1)) && !NameUtil.isWordSeparator(myPattern[patternIndex + 1])) {
return null;
}
final FList<TextRange> ranges = matchName(name, patternIndex + 1, nextStart);
if (ranges != null) {
return prependRange(ranges, nameIndex, 1);
}
return null;
}
return matchName(name, patternIndex, nextStart);
}
@Nullable
private FList<TextRange> skipChars(String name, int patternIndex, int nameIndex, boolean maySkipNextChar) {
while ('*' == myPattern[patternIndex]) {
patternIndex++;
if (patternIndex == myPattern.length) {
return FList.emptyList();
}
}
char nextChar = myPattern[patternIndex];
boolean upper = Character.isUpperCase(myPattern[patternIndex]);
int fromIndex = nameIndex;
while (true) {
int next = StringUtil.indexOfIgnoreCase(name, nextChar, fromIndex);
if (next < 0) {
break;
}
if (upper && next > 0 && !Character.isUpperCase(name.charAt(next)) && myOptions != NameUtil.MatchingCaseSensitivity.NONE) {
fromIndex = next + 1;
continue;
}
FList<TextRange> ranges = matchName(name, patternIndex, next);
if (ranges != null) {
return ranges;
}
if (!maySkipNextChar) {
return null;
}
fromIndex = next + 1;
}
return null;
}
@Nullable
private FList<TextRange> skipWords(String name, int patternIndex, int nameIndex) {
while (' ' == myPattern[patternIndex]) {
patternIndex++;
if (patternIndex == myPattern.length) {
return null;
}
}
if (nameIndex == 0 || NameUtil.isWordStart(name, nameIndex)) {
FList<TextRange> ranges = matchName(name, patternIndex, nameIndex);
if (ranges != null) {
return ranges;
}
}
boolean separatorInPattern = NameUtil.isWordSeparator(myPattern[patternIndex]);
int fromIndex = nameIndex;
while (fromIndex < name.length()) {
int next = separatorInPattern ? name.indexOf(myPattern[patternIndex], fromIndex) : NameUtil.nextWord(name, fromIndex);
if (next < 0) {
break;
}
FList<TextRange> ranges = matchName(name, patternIndex, next);
if (ranges != null) {
return ranges;
}
fromIndex = next;
if (separatorInPattern) {
fromIndex++;
}
}
return null;
}
public int matchingDegree(String name) {
Iterable<TextRange> iterable = matchingFragments(name);
if (iterable == null) return Integer.MIN_VALUE;
int fragmentCount = 0;
int matchingCase = 0;
CharArrayCharSequence seq = new CharArrayCharSequence(myPattern);
int p = -1;
TextRange first = null;
for (TextRange range : iterable) {
if (first == null) {
first = range;
}
for (int i = range.getStartOffset(); i < range.getEndOffset(); i++) {
char c = name.charAt(i);
p = StringUtil.indexOf(seq, c, p + 1, myPattern.length, false);
if (p < 0) {
break;
}
if (Character.isUpperCase(myPattern[p]) || i == range.getStartOffset()) {
matchingCase += c == myPattern[p] ? 1 : 0;
}
}
fragmentCount++;
}
if (first == null) {
return 0;
}
int commonStart = 0;
while (commonStart < name.length() && commonStart < myPattern.length && name.charAt(commonStart) == myPattern[commonStart]) {
commonStart++;
}
int startIndex = first.getStartOffset();
boolean prefixMatching = isStartMatch(name, startIndex);
boolean middleWordStart = !prefixMatching && NameUtil.isWordStart(name, first.getStartOffset());
return -fragmentCount + matchingCase * 10 + commonStart - startIndex + (prefixMatching ? 2 : middleWordStart ? 1 : 0) * 100;
}
public boolean isStartMatch(String name) {
Iterable<TextRange> fragments = matchingFragments(name);
if (fragments != null) {
Iterator<TextRange> iterator = fragments.iterator();
if (!iterator.hasNext() || isStartMatch(name, iterator.next().getStartOffset())) {
return true;
}
}
return false;
}
private static boolean isStartMatch(String name, int startIndex) {
for (int i = 0; i < startIndex; i++) {
if (!NameUtil.isWordSeparator(name.charAt(i))) {
return false;
}
}
return true;
}
@Override
public boolean matches(String name) {
return matchingFragments(name) != null;
}
@Nullable
public Iterable<TextRange> matchingFragments(String name) {
if (name.isEmpty()) {
return myPattern.length == 0 ? Collections.<TextRange>emptyList() : null;
}
return matchName(name, 0, 0);
}
}
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.FList;
import com.intellij.util.text.CharArrayCharSequence;
import com.intellij.util.text.Matcher;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.Iterator;
/**
* @author peter
*/
public class MinusculeMatcher implements Matcher {
private final char[] myPattern;
private final NameUtil.MatchingCaseSensitivity myOptions;
public MinusculeMatcher(String pattern, NameUtil.MatchingCaseSensitivity options) {
myOptions = options;
myPattern = StringUtil.trimEnd(pattern, "* ").replaceAll(":", "\\*:").toCharArray();
}
@Nullable
private FList<TextRange> matchName(String name, int patternIndex, int nameIndex) {
if (patternIndex == myPattern.length) {
return FList.emptyList();
}
if ('*' == myPattern[patternIndex]) {
return skipChars(name, patternIndex, nameIndex, true);
}
if (nameIndex == name.length()) {
return null;
}
if ('.' == myPattern[patternIndex] && name.charAt(nameIndex) != '.') {
return skipChars(name, patternIndex, nameIndex, false);
}
if (' ' == myPattern[patternIndex] && patternIndex != myPattern.length - 1) {
return skipWords(name, patternIndex, nameIndex);
}
if ((patternIndex == 0 || patternIndex == 1 && myPattern[0] == ' ' && nameIndex == 0) &&
myOptions != NameUtil.MatchingCaseSensitivity.NONE && name.charAt(nameIndex) != myPattern[patternIndex]) {
return null;
}
if (NameUtil.isWordSeparator(name.charAt(nameIndex))) {
return skipSeparators(name, patternIndex, nameIndex);
}
if (StringUtil.toLowerCase(name.charAt(nameIndex)) != StringUtil.toLowerCase(myPattern[patternIndex])) {
if (Character.isDigit(name.charAt(nameIndex)) && nameIndex > 0 || (name.charAt(nameIndex) == '.' && name.indexOf('.', nameIndex + 1) > 0)) {
return matchName(name, patternIndex, nameIndex + 1);
}
return null;
}
if (myOptions == NameUtil.MatchingCaseSensitivity.ALL && name.charAt(nameIndex) != myPattern[patternIndex]) {
return null;
}
int nextStart = NameUtil.nextWord(name, nameIndex);
int lastUpper = NameUtil.isWordStart(myPattern[patternIndex]) ? 0 : -1;
int i = 1;
while (true) {
if (patternIndex + i == myPattern.length || i + nameIndex == nextStart) {
break;
}
char p = myPattern[patternIndex + i];
char w = name.charAt(i + nameIndex);
if (lastUpper == i - 1 && NameUtil.isWordStart(p) && myOptions != NameUtil.MatchingCaseSensitivity.ALL) {
if (p == w) {
lastUpper = i;
}
p = StringUtil.toLowerCase(p);
}
if (myOptions != NameUtil.MatchingCaseSensitivity.ALL) {
w = StringUtil.toLowerCase(w);
}
if (w != p) {
break;
}
i++;
}
if (isFinalSpaceMatch(name, patternIndex, nameIndex, nextStart, i)) {
return FList.<TextRange>emptyList().prepend(TextRange.from(nameIndex, i));
}
return matchAfterFragment(name, patternIndex, nameIndex, nextStart, lastUpper, i);
}
private boolean isFinalSpaceMatch(String name, int patternIndex, int nameIndex, int nextStart, int i) {
return nextStart == name.length() &&
patternIndex + i == myPattern.length - 1 &&
' ' == myPattern[patternIndex + i] &&
(i == 1 && NameUtil.isWordStart(myPattern[patternIndex]) || i + nameIndex == name.length());
}
@Nullable
private FList<TextRange> matchAfterFragment(String name, int patternIndex, int nameIndex, int nextStart, int lastUpper, int matchLen) {
boolean star = patternIndex + matchLen < myPattern.length && myPattern[patternIndex + matchLen] == '*';
if (lastUpper >= 0) {
FList<TextRange> ranges = matchName(name, patternIndex + lastUpper + 1, star && matchLen == lastUpper ? nameIndex + lastUpper : nextStart);
if (ranges != null) {
return prependRange(ranges, nameIndex, lastUpper + 1);
}
}
int trial = matchLen;
while (trial > 0) {
FList<TextRange> ranges = matchName(name, patternIndex + trial, nextStart);
if (ranges != null) {
return prependRange(ranges, nameIndex, trial);
}
trial--;
}
FList<TextRange> ranges = matchName(name, patternIndex + matchLen, nameIndex + matchLen);
if (ranges != null) {
return prependRange(ranges, nameIndex, matchLen);
}
return null;
}
private static FList<TextRange> prependRange(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));
}
@Nullable
private FList<TextRange> skipSeparators(String name, int patternIndex, int nameIndex) {
int nextStart = NameUtil.nextWord(name, nameIndex);
assert nextStart - nameIndex == 1 : "'" + name + "'" + nameIndex + " " + nextStart;
char p = myPattern[patternIndex];
if (NameUtil.isWordSeparator(p)) {
if (myOptions != NameUtil.MatchingCaseSensitivity.NONE &&
nameIndex == 0 && name.length() > 1 && patternIndex + 1 < myPattern.length &&
NameUtil.isWordSeparator(name.charAt(1)) && !NameUtil.isWordSeparator(myPattern[patternIndex + 1])) {
return null;
}
final FList<TextRange> ranges = matchName(name, patternIndex + 1, nextStart);
if (ranges != null) {
return prependRange(ranges, nameIndex, 1);
}
return null;
}
return matchName(name, patternIndex, nextStart);
}
@Nullable
private FList<TextRange> skipChars(String name, int patternIndex, int nameIndex, boolean maySkipNextChar) {
while ('*' == myPattern[patternIndex]) {
patternIndex++;
if (patternIndex == myPattern.length) {
return FList.emptyList();
}
}
char nextChar = myPattern[patternIndex];
boolean upper = Character.isUpperCase(myPattern[patternIndex]);
int fromIndex = nameIndex;
while (true) {
int next = StringUtil.indexOfIgnoreCase(name, nextChar, fromIndex);
if (next < 0) {
break;
}
if (upper && next > 0 && !Character.isUpperCase(name.charAt(next))) {
fromIndex = next + 1;
continue;
}
FList<TextRange> ranges = matchName(name, patternIndex, next);
if (ranges != null) {
return ranges;
}
if (!maySkipNextChar) {
return null;
}
fromIndex = next + 1;
}
return null;
}
@Nullable
private FList<TextRange> skipWords(String name, int patternIndex, int nameIndex) {
while (' ' == myPattern[patternIndex]) {
patternIndex++;
if (patternIndex == myPattern.length) {
return null;
}
}
if (nameIndex == 0 || NameUtil.isWordStart(name, nameIndex)) {
FList<TextRange> ranges = matchName(name, patternIndex, nameIndex);
if (ranges != null) {
return ranges;
}
}
boolean separatorInPattern = NameUtil.isWordSeparator(myPattern[patternIndex]);
int fromIndex = nameIndex;
while (fromIndex < name.length()) {
int next = separatorInPattern ? name.indexOf(myPattern[patternIndex], fromIndex) : NameUtil.nextWord(name, fromIndex);
if (next < 0) {
break;
}
FList<TextRange> ranges = matchName(name, patternIndex, next);
if (ranges != null) {
return ranges;
}
fromIndex = next;
if (separatorInPattern) {
fromIndex++;
}
}
return null;
}
public int matchingDegree(String name) {
Iterable<TextRange> iterable = matchingFragments(name);
if (iterable == null) return Integer.MIN_VALUE;
int fragmentCount = 0;
int matchingCase = 0;
CharArrayCharSequence seq = new CharArrayCharSequence(myPattern);
int p = -1;
TextRange first = null;
for (TextRange range : iterable) {
if (first == null) {
first = range;
}
for (int i = range.getStartOffset(); i < range.getEndOffset(); i++) {
char c = name.charAt(i);
p = StringUtil.indexOf(seq, c, p + 1, myPattern.length, false);
if (p < 0) {
break;
}
if (Character.isUpperCase(myPattern[p]) || i == range.getStartOffset()) {
matchingCase += c == myPattern[p] ? 1 : 0;
}
}
fragmentCount++;
}
if (first == null) {
return 0;
}
int commonStart = 0;
while (commonStart < name.length() && commonStart < myPattern.length && name.charAt(commonStart) == myPattern[commonStart]) {
commonStart++;
}
int startIndex = first.getStartOffset();
boolean prefixMatching = isStartMatch(name, startIndex);
boolean middleWordStart = !prefixMatching && NameUtil.isWordStart(name, first.getStartOffset());
return -fragmentCount + matchingCase * 10 + commonStart - startIndex + (prefixMatching ? 2 : middleWordStart ? 1 : 0) * 100;
}
public boolean isStartMatch(String name) {
Iterable<TextRange> fragments = matchingFragments(name);
if (fragments != null) {
Iterator<TextRange> iterator = fragments.iterator();
if (!iterator.hasNext() || isStartMatch(name, iterator.next().getStartOffset())) {
return true;
}
}
return false;
}
private static boolean isStartMatch(String name, int startIndex) {
for (int i = 0; i < startIndex; i++) {
if (!NameUtil.isWordSeparator(name.charAt(i))) {
return false;
}
}
return true;
}
@Override
public boolean matches(String name) {
return matchingFragments(name) != null;
}
@Nullable
public Iterable<TextRange> matchingFragments(String name) {
if (name.isEmpty()) {
return myPattern.length == 0 ? Collections.<TextRange>emptyList() : null;
}
return matchName(name, 0, 0);
}
}