diff --git a/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java b/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java index 9c14f0ad0de3..36de7bf79152 100644 --- a/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java +++ b/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java @@ -929,11 +929,11 @@ public class FindManagerTest extends DaemonAnalyzerTestCase { public void testRegexReplacementStringForIndices() { assertEquals("public static MyType my = 1;", FindInProjectUtil.buildStringToFindForIndicesFromRegExp("public static (@A)? MyType my\\w+? = 1;", myProject)); - assertEquals(" Foo ", FindInProjectUtil.buildStringToFindForIndicesFromRegExp("\\bFoo\\b", myProject)); + assertEquals("Foo", FindInProjectUtil.buildStringToFindForIndicesFromRegExp("\\bFoo\\b", myProject)); assertEquals("", FindInProjectUtil.buildStringToFindForIndicesFromRegExp("foo|bar", myProject)); - assertEquals(" Exit Foo Bar Baz", FindInProjectUtil.buildStringToFindForIndicesFromRegExp("\\nExit\\tFoo\\rBar\\fBaz", myProject)); - assertEquals(" Foo Bar Baz Exit", FindInProjectUtil.buildStringToFindForIndicesFromRegExp("\\012Foo\\u000ABar\\x0ABaz\\aExit", myProject)); - assertEquals(" Foo Bar BazCooBoo", FindInProjectUtil.buildStringToFindForIndicesFromRegExp("\\1Foo\\sBar\\DBaz\\QCoo\\E\\QBoo", myProject)); + assertEquals("Exit Foo Bar Baz", FindInProjectUtil.buildStringToFindForIndicesFromRegExp("\\nExit\\tFoo\\rBar\\fBaz", myProject)); + assertEquals("Foo Bar Baz Exit", FindInProjectUtil.buildStringToFindForIndicesFromRegExp("\\012Foo\\u000ABar\\x0ABaz\\aExit", myProject)); + assertEquals("Foo Bar BazCooBoo", FindInProjectUtil.buildStringToFindForIndicesFromRegExp("\\1Foo\\sBar\\DBaz\\QCoo\\E\\QBoo", myProject)); } public void testCreateFileMaskCondition() { diff --git a/platform/indexing-api/src/com/intellij/psi/search/IndexPattern.java b/platform/indexing-api/src/com/intellij/psi/search/IndexPattern.java index d21f69f20827..d7d67a14093e 100644 --- a/platform/indexing-api/src/com/intellij/psi/search/IndexPattern.java +++ b/platform/indexing-api/src/com/intellij/psi/search/IndexPattern.java @@ -15,10 +15,13 @@ */ package com.intellij.psi.search; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collections; +import java.util.List; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; @@ -33,6 +36,7 @@ public class IndexPattern { private Pattern myOptimizedIndexingPattern; private boolean myCaseSensitive; private Pattern myPattern; + private @NotNull List myStringsToFindFirst = Collections.emptyList(); /** * Creates an instance of an index pattern. @@ -59,6 +63,11 @@ public class IndexPattern { return myOptimizedIndexingPattern; } + @NotNull + public List getWordsToFindFirst() { + return myStringsToFindFirst; + } + public boolean isCaseSensitive() { return myCaseSensitive; } @@ -86,10 +95,17 @@ public class IndexPattern { String optimizedPattern = myPatternString; optimizedPattern = StringUtil.trimStart(optimizedPattern, ".*"); myOptimizedIndexingPattern = Pattern.compile(optimizedPattern, flags); + try { + //myStringsToFindFirst = IndexPatternOptimizer.getInstance().extractStringsToFind(myPatternString); + } + catch (Throwable throwable) { + Logger.getInstance(IndexPattern.class).info("OLOLO", throwable); + } } catch(PatternSyntaxException e){ myPattern = null; myOptimizedIndexingPattern = null; + myStringsToFindFirst = Collections.emptyList(); } } diff --git a/platform/indexing-api/src/com/intellij/psi/search/IndexPatternOptimizer.java b/platform/indexing-api/src/com/intellij/psi/search/IndexPatternOptimizer.java new file mode 100644 index 000000000000..31a71fff82b2 --- /dev/null +++ b/platform/indexing-api/src/com/intellij/psi/search/IndexPatternOptimizer.java @@ -0,0 +1,18 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.psi.search; + +import com.intellij.openapi.components.ServiceManager; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +@ApiStatus.Internal +public interface IndexPatternOptimizer { + + static IndexPatternOptimizer getInstance() { + return ServiceManager.getService(IndexPatternOptimizer.class); + } + + @NotNull List extractStringsToFind(@NotNull String regexp); +} diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/PlainTextIdIndexer.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/PlainTextIdIndexer.java new file mode 100644 index 000000000000..661c2114614a --- /dev/null +++ b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/PlainTextIdIndexer.java @@ -0,0 +1,55 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.psi.impl.cache.impl.id; + +import com.intellij.openapi.fileTypes.PlainTextFileType; +import com.intellij.openapi.util.Key; +import com.intellij.psi.impl.cache.impl.todo.TodoIndexers; +import com.intellij.psi.search.UsageSearchContext; +import com.intellij.util.indexing.FileContent; +import com.intellij.util.indexing.IdDataConsumer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; + +public class PlainTextIdIndexer implements IdIndexer { + private static final Key> ID_INDEX_DATA_KEY = Key.create("plain.text.id.index"); + + @Override + @NotNull + public Map map(@NotNull final FileContent inputData) { + return getIdIndexData(inputData); + } + + @NotNull + public static Map getIdIndexData(@NotNull FileContent content) { + Map idIndexData = content.getUserData(ID_INDEX_DATA_KEY); + if (idIndexData != null) { + content.putUserData(ID_INDEX_DATA_KEY, null); + return idIndexData; + } + + IdDataConsumer consumer = new IdDataConsumer(); + CharSequence text = content.getContentAsText(); + IdTableBuilding.scanWords(new IdTableBuilding.ScanWordProcessor() { + @Override + public void run(final CharSequence chars11, char @Nullable [] charsArray, final int start, final int end) { + if (charsArray != null) { + consumer.addOccurrence(charsArray, start, end, UsageSearchContext.IN_PLAIN_TEXT); + } + else { + consumer.addOccurrence(chars11, start, end, UsageSearchContext.IN_PLAIN_TEXT); + } + } + }, text, 0, text.length()); + + Map result = consumer.getResult(); + + if (TodoIndexers.needsTodoIndex(content.getFile()) && + IdIndex.isIndexable(PlainTextFileType.INSTANCE)) { + content.putUserData(ID_INDEX_DATA_KEY, result); + } + + return result; + } +} diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/PlainTextIndexer.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/PlainTextIndexer.java deleted file mode 100644 index 558f863d3748..000000000000 --- a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/PlainTextIndexer.java +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package com.intellij.psi.impl.cache.impl.id; - -import com.intellij.psi.search.UsageSearchContext; -import com.intellij.util.indexing.FileContent; -import com.intellij.util.indexing.IdDataConsumer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Map; - -public class PlainTextIndexer implements IdIndexer { - @Override - @NotNull - public Map map(@NotNull final FileContent inputData) { - final IdDataConsumer consumer = new IdDataConsumer(); - final CharSequence chars = inputData.getContentAsText(); - IdTableBuilding.scanWords(new IdTableBuilding.ScanWordProcessor() { - @Override - public void run(final CharSequence chars11, char @Nullable [] charsArray, final int start, final int end) { - if (charsArray != null) { - consumer.addOccurrence(charsArray, start, end, (int)UsageSearchContext.IN_PLAIN_TEXT); - } - else { - consumer.addOccurrence(chars11, start, end, (int)UsageSearchContext.IN_PLAIN_TEXT); - } - } - }, chars, 0, chars.length()); - return consumer.getResult(); - } -} diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/todo/PlainTextTodoIndexer.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/todo/PlainTextTodoIndexer.java index 4e55dfdd815f..d19fbeedf1bc 100644 --- a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/todo/PlainTextTodoIndexer.java +++ b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/todo/PlainTextTodoIndexer.java @@ -19,12 +19,15 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.patterns.StringPattern; import com.intellij.psi.impl.cache.impl.IndexPatternUtil; import com.intellij.psi.impl.cache.impl.OccurrenceConsumer; +import com.intellij.psi.impl.cache.impl.id.IdIndexEntry; +import com.intellij.psi.impl.cache.impl.id.PlainTextIdIndexer; import com.intellij.psi.search.IndexPattern; import com.intellij.util.indexing.FileContent; import org.jetbrains.annotations.NotNull; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -41,6 +44,10 @@ public class PlainTextTodoIndexer extends VersionedTodoIndexer { String chars = inputData.getContentAsText().toString(); // matching strings is faster than HeapCharBuffer OccurrenceConsumer occurrenceConsumer = new OccurrenceConsumer(null, true); for (IndexPattern indexPattern : indexPatterns) { + if (!idIndexContainAllWords(indexPattern.getWordsToFindFirst(), indexPattern.isCaseSensitive(), inputData)) { + continue; + } + Pattern pattern = indexPattern.getOptimizedIndexingPattern(); try { if (pattern != null) { @@ -66,4 +73,8 @@ public class PlainTextTodoIndexer extends VersionedTodoIndexer { return map; } + private static boolean idIndexContainAllWords(@NotNull List words, boolean caseSensitive, @NotNull FileContent content) { + Map idIndexData = PlainTextIdIndexer.getIdIndexData(content); + return words.stream().allMatch(word -> idIndexData.containsKey(new IdIndexEntry(word, caseSensitive))); + } } diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndexers.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndexers.java index 89cec6d4763b..91fb591e6e95 100644 --- a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndexers.java +++ b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/todo/TodoIndexers.java @@ -27,6 +27,10 @@ public final class TodoIndexers extends FileTypeExtension { final List topLevelRegExpChars = getTopLevelRegExpChars("a", project); - if (topLevelRegExpChars.size() != 1) return ""; + if (topLevelRegExpChars.size() != 1) return " "; // leave only top level regExpChars - return StringUtil.join(getTopLevelRegExpChars(stringToFind, project), new Function() { - final Class regExpCharPsiClass = topLevelRegExpChars.get(0).getClass(); - @Override - public String fun(PsiElement element) { - if (regExpCharPsiClass.isInstance(element)) { - String text = element.getText(); + final Class regExpCharPsiClass = topLevelRegExpChars.get(0).getClass(); + return getTopLevelRegExpChars(regexp, project) + .stream() + .map(psi -> { + if (regExpCharPsiClass.isInstance(psi)) { + String text = psi.getText(); if (!text.startsWith("\\")) return text; } return " "; - } - }, ""); + }) + .collect(Collectors.joining()); }); } + @NotNull + public static String buildStringToFindForIndicesFromRegExp(@NotNull String stringToFind, @NotNull Project project) { + if (!Registry.is("idea.regexp.search.uses.indices")) return ""; + + return StringUtil.trim(StringUtil.join(extractStringToFind(stringToFind, project), " ")); + } + public static void initStringToFindFromDataContext(FindModel findModel, @NotNull DataContext dataContext) { Editor editor = CommonDataKeys.EDITOR.getData(dataContext); FindUtil.initStringToFindWithSelection(findModel, editor); diff --git a/platform/lang-impl/src/com/intellij/psi/search/IndexPatternOptimizerImpl.java b/platform/lang-impl/src/com/intellij/psi/search/IndexPatternOptimizerImpl.java new file mode 100644 index 000000000000..4e0284684da8 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/psi/search/IndexPatternOptimizerImpl.java @@ -0,0 +1,26 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.psi.search; + +import com.intellij.find.impl.FindInProjectUtil; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.project.ProjectManager; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.PlatformUtils; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +@ApiStatus.Internal +public class IndexPatternOptimizerImpl implements IndexPatternOptimizer { + @Override + public @NotNull List extractStringsToFind(@NotNull String regexp) { + // TODO some datagrip tests are not passed with unknown reason (no exception in logs but it's) + if (ApplicationManager.getApplication().isUnitTestMode() && PlatformUtils.isDataGrip()) { + return Collections.emptyList(); + } + String stringToFind = FindInProjectUtil.extractStringToFind(regexp, ProjectManager.getInstance().getDefaultProject()); + return StringUtil.getWordsIn(stringToFind); + } +} diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index 27759e320abb..42ef0923e0ac 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -239,6 +239,9 @@ + + @@ -571,7 +574,7 @@ - + diff --git a/plugins/textmate/src/META-INF/plugin.xml b/plugins/textmate/src/META-INF/plugin.xml index 10b933c98248..e6794fb37d92 100644 --- a/plugins/textmate/src/META-INF/plugin.xml +++ b/plugins/textmate/src/META-INF/plugin.xml @@ -34,7 +34,7 @@ - +