From b4ff3fb3db0f06bc84bff45dc4eb51de3d46b12f Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Thu, 31 Jul 2014 17:59:50 +0200 Subject: [PATCH] group text occurrences in comments literals in different groups (IDEA-54427 IDEA-114331 --- .../com/intellij/find/FindManagerTest.java | 43 +++++++ .../intellij/find/impl/FindManagerImpl.java | 106 ++++++++++++++++-- .../find/impl/FindResultUsageInfo.java | 2 +- 3 files changed, 139 insertions(+), 12 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java b/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java index 33f43ef93fa7..2f6c4216e4ed 100644 --- a/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java +++ b/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java @@ -27,6 +27,7 @@ import com.intellij.openapi.application.ex.PathManagerEx; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.fileTypes.PlainTextFileType; import com.intellij.openapi.projectRoots.Sdk; @@ -38,6 +39,7 @@ import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.GlobalSearchScopes; import com.intellij.psi.search.LocalSearchScope; import com.intellij.testFramework.IdeaTestUtil; import com.intellij.testFramework.LightVirtualFile; @@ -301,6 +303,9 @@ public class FindManagerTest extends DaemonAnalyzerTestCase { findModel.setGlobal(true); findModel.setMultipleFiles(true); findModel.setCustomScope(true); + OpenFileDescriptor descriptor = new OpenFileDescriptor(myProject, nonProjectFile); + descriptor.navigate(true); + GlobalSearchScopes.openFilesScope(myProject); findModel.setCustomScope(new GlobalSearchScope.FilesScope(myProject, ContainerUtil.list(nonProjectFile))); assertSize(1, findUsages(findModel)); @@ -650,4 +655,42 @@ public class FindManagerTest extends DaemonAnalyzerTestCase { findModel.setWholeWordsOnly(true); assertSize(1, findUsages(findModel)); } + + public void testFindExceptComments() { + FindModel findModel = FindManagerTestUtils.configureFindModel("done"); + + String prefix = "/*"; + String text = prefix + "done*/done"; + + findModel.setSearchContext(FindModel.SearchContext.EXCEPT_COMMENTS); + LightVirtualFile file = new LightVirtualFile("A.java", text); + + FindResult findResult = myFindManager.findString(text, prefix.length(), findModel, file); + assertTrue(findResult.isStringFound()); + assertTrue(findResult.getStartOffset() > prefix.length()); + + findModel.setRegularExpressions(true); + findResult = myFindManager.findString(text, prefix.length(), findModel, file); + assertTrue(findResult.isStringFound()); + assertTrue(findResult.getStartOffset() > prefix.length()); + } + + public void testFindExceptLiterals() { + FindModel findModel = FindManagerTestUtils.configureFindModel("done"); + + String prefix = "\""; + String text = prefix + "done\"done"; + + findModel.setSearchContext(FindModel.SearchContext.EXCEPT_STRINGS); + LightVirtualFile file = new LightVirtualFile("A.java", text); + + FindResult findResult = myFindManager.findString(text, prefix.length(), findModel, file); + assertTrue(findResult.isStringFound()); + assertTrue(findResult.getStartOffset() > prefix.length()); + + findModel.setRegularExpressions(true); + findResult = myFindManager.findString(text, prefix.length(), findModel, file); + assertTrue(findResult.isStringFound()); + assertTrue(findResult.getStartOffset() > prefix.length()); + } } diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java index 05a40ab19ec5..c1c5185f3d7a 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java @@ -62,6 +62,7 @@ import com.intellij.usages.UsageViewManager; import com.intellij.usages.impl.SyntaxHighlighterOverEditorHighlighter; import com.intellij.util.Consumer; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.Predicate; import com.intellij.util.messages.MessageBus; import com.intellij.util.text.CharArrayUtil; import com.intellij.util.text.StringSearcher; @@ -312,19 +313,23 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo LOG.debug(model.toString()); } - final char[] textArray = CharArrayUtil.fromSequenceWithoutCopying(text); + return findStringLoop(text, offset, model, file, getFindContextPredicate(model, file, text)); + } + private FindResult findStringLoop(CharSequence text, int offset, FindModel model, VirtualFile file, @Nullable Predicate filter) { + final char[] textArray = CharArrayUtil.fromSequenceWithoutCopying(text); while(true) { FindResult result = doFindString(text, textArray, offset, model, file); - - if (!model.isWholeWordsOnly()) { - return result; - } - if (!result.isStringFound()){ - return result; - } - if (isWholeWord(text, result.getStartOffset(), result.getEndOffset())){ - return result; + if (filter == null || filter.apply(result)) { + if (!model.isWholeWordsOnly()) { + return result; + } + if (!result.isStringFound()) { + return result; + } + if (isWholeWord(text, result.getStartOffset(), result.getEndOffset())) { + return result; + } } offset = model.isForward() ? result.getStartOffset() + 1 : result.getEndOffset() - 1; @@ -332,6 +337,80 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo } } + private class FindExceptCommentsOrLiteralsData implements Predicate { + private final VirtualFile myFile; + private final FindModel myFindModel; + private final TreeMap mySkipRangesSet; + + private FindExceptCommentsOrLiteralsData(VirtualFile file, FindModel model, CharSequence text) { + myFile = file; + myFindModel = model.clone(); + + TreeMap result = new TreeMap(); + + if (model.isExceptComments() || model.isExceptCommentsAndStringLiterals()) { + addRanges(file, model, text, result, FindModel.SearchContext.IN_COMMENTS); + } + + if (model.isExceptStringLiterals() || model.isExceptCommentsAndStringLiterals()) { + addRanges(file, model, text, result, FindModel.SearchContext.IN_STRINGS); + } + + mySkipRangesSet = result; + } + + private void addRanges(VirtualFile file, + FindModel model, + CharSequence text, + TreeMap result, + FindModel.SearchContext searchContext) { + FindModel clonedModel = model.clone(); + clonedModel.setSearchContext(searchContext); + clonedModel.setForward(true); + int offset = 0; + + while(true) { + FindResult customResult = findStringLoop(text, offset, clonedModel, file, null); + if (!customResult.isStringFound()) break; + result.put(customResult.getStartOffset(), customResult.getEndOffset()); + offset = Math.max(customResult.getEndOffset(), offset + 1); // avoid loop for zero size reg exps matches + if (offset >= text.length()) break; + } + } + + boolean isAcceptableFor(FindModel model, VirtualFile file) { + return Comparing.equal(myFile, file) && myFindModel.equals(model); + } + + @Override + public boolean apply(@Nullable FindResult input) { + if (input == null || !input.isStringFound()) return true; + NavigableMap map = mySkipRangesSet.headMap(input.getStartOffset(), true); + for(Map.Entry e:map.descendingMap().entrySet()) { + if (e.getKey() <= input.getStartOffset() && e.getValue() >= input.getEndOffset()) return false; + if (e.getValue() <= input.getStartOffset()) break; + } + return true; + } + } + private static Key ourExceptCommentsOrLiteralsDataKey = Key.create("except.comments.literals.search.data"); + + private Predicate getFindContextPredicate(@NotNull FindModel model, VirtualFile file, CharSequence text) { + if (file == null) return null; + FindModel.SearchContext context = model.getSearchContext(); + if( context == FindModel.SearchContext.ANY || context == FindModel.SearchContext.IN_COMMENTS || + context == FindModel.SearchContext.IN_STRINGS) { + return null; + } + + FindExceptCommentsOrLiteralsData data = model.getUserData(ourExceptCommentsOrLiteralsDataKey); + if (data == null || !data.isAcceptableFor(model, file)) { + model.putUserData(ourExceptCommentsOrLiteralsDataKey, data = new FindExceptCommentsOrLiteralsData(file, model, text)); + } + + return data; + } + @Override public int showMalformedReplacementPrompt(@NotNull FindModel model, String title, MalformedReplacementStringException exception) { return showPromptDialogImpl(model, title, exception); @@ -415,6 +494,11 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo return new StringSearcher(model.getStringToFind(), model.isCaseSensitive(), model.isForward()); } + public static void clearPreviousFindData(FindModel model) { + model.putUserData(ourCommentsLiteralsSearchDataKey, null); + model.putUserData(ourExceptCommentsOrLiteralsDataKey, null); + } + private static class CommentsLiteralsSearchData { final VirtualFile lastFile; int startOffset = 0; @@ -439,7 +523,7 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo } } - public static final Key ourCommentsLiteralsSearchDataKey = Key.create("comments.literals.search.data"); + private static final Key ourCommentsLiteralsSearchDataKey = Key.create("comments.literals.search.data"); @NotNull private FindResult findInCommentsAndLiterals(@NotNull CharSequence text, diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindResultUsageInfo.java b/platform/lang-impl/src/com/intellij/find/impl/FindResultUsageInfo.java index 6baf8cc4fca8..ee8d98422250 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindResultUsageInfo.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindResultUsageInfo.java @@ -80,7 +80,7 @@ public class FindResultUsageInfo extends UsageInfo { Long data = myFindModel.getUserData(ourDocumentTimestampKey); if (data == null || data != myTimestamp) { data = myTimestamp; - myFindModel.putUserData(FindManagerImpl.ourCommentsLiteralsSearchDataKey, null); + FindManagerImpl.clearPreviousFindData(myFindModel); } myFindModel.putUserData(ourDocumentTimestampKey, data); FindResult result;