private static void logStats(Collection<PsiFile> otherFiles, long start) { long time = System.currentTimeMillis() - start; final Multiset<String> stats = HashMultiset.create(); for (PsiFile file : otherFiles) { stats.add( StringUtil.notNullize(file.getViewProvider().getVirtualFile().getExtension()) .toLowerCase()); } List<String> extensions = ContainerUtil.newArrayList(stats.elementSet()); Collections.sort( extensions, new Comparator<String>() { @Override public int compare(String o1, String o2) { return stats.count(o2) - stats.count(o1); } }); String message = "Search in " + otherFiles.size() + " files with unknown types took " + time + "ms.\n" + "Mapping their extensions to an existing file type (e.g. Plain Text) might speed up the search.\n" + "Most frequent non-indexed file extensions: "; for (int i = 0; i < Math.min(10, extensions.size()); i++) { String extension = extensions.get(i); message += extension + "(" + stats.count(extension) + ") "; } LOG.info(message); }
@NotNull private static Set<VirtualFile> getLocalScopeFiles(@NotNull LocalSearchScope scope) { Set<VirtualFile> files = new LinkedHashSet<VirtualFile>(); for (PsiElement element : scope.getScope()) { PsiFile file = element.getContainingFile(); if (file != null) { ContainerUtil.addIfNotNull(files, file.getVirtualFile()); } } return files; }
@NotNull public static GlobalSearchScope getMaximalScope(@NotNull FindUsagesHandler handler) { PsiElement element = handler.getPsiElement(); Project project = element.getProject(); PsiFile file = element.getContainingFile(); if (file != null && ProjectFileIndex.SERVICE .getInstance(project) .isInContent(file.getViewProvider().getVirtualFile())) { return GlobalSearchScope.projectScope(project); } return GlobalSearchScope.allScope(project); }
private void findUsagesInEditor( @NotNull UsageInfoToUsageConverter.TargetElementsDescriptor descriptor, @NotNull FindUsagesHandler handler, @NotNull PsiFile scopeFile, @NotNull FileSearchScope direction, @NotNull final FindUsagesOptions findUsagesOptions, @NotNull FileEditor fileEditor) { initLastSearchElement(findUsagesOptions, descriptor); clearStatusBar(); final FileEditorLocation currentLocation = fileEditor.getCurrentLocation(); final UsageSearcher usageSearcher = createUsageSearcher(descriptor, handler, findUsagesOptions, scopeFile); AtomicBoolean usagesWereFound = new AtomicBoolean(); Usage fUsage = findSiblingUsage(usageSearcher, direction, currentLocation, usagesWereFound, fileEditor); if (fUsage != null) { fUsage.navigate(true); fUsage.selectInEditor(); } else if (!usagesWereFound.get()) { String message = getNoUsagesFoundMessage(descriptor.getPrimaryElements()[0]) + " in " + scopeFile.getName(); showHintOrStatusBarMessage(message, fileEditor); } else { fileEditor.putUserData(KEY_START_USAGE_AGAIN, VALUE_START_USAGE_AGAIN); showHintOrStatusBarMessage( getSearchAgainMessage(descriptor.getPrimaryElements()[0], direction), fileEditor); } }
private static int addToUsages( @NotNull Document document, @NotNull Processor<UsageInfo> consumer, @NotNull FindModel findModel, @NotNull final PsiFile psiFile, @NotNull int[] offsetRef, int maxUsages) { int count = 0; CharSequence text = document.getCharsSequence(); int textLength = document.getTextLength(); int offset = offsetRef[0]; Project project = psiFile.getProject(); FindManager findManager = FindManager.getInstance(project); while (offset < textLength) { FindResult result = findManager.findString(text, offset, findModel, psiFile.getVirtualFile()); if (!result.isStringFound()) break; final SearchScope customScope = findModel.getCustomScope(); if (customScope instanceof LocalSearchScope) { final TextRange range = new TextRange(result.getStartOffset(), result.getEndOffset()); if (!((LocalSearchScope) customScope).containsRange(psiFile, range)) break; } UsageInfo info = new FindResultUsageInfo(findManager, psiFile, offset, findModel, result); if (!consumer.process(info)) { throw new ProcessCanceledException(); } count++; final int prevOffset = offset; offset = result.getEndOffset(); if (prevOffset == offset) { // for regular expr the size of the match could be zero -> could be infinite loop in finding // usages! ++offset; } if (maxUsages > 0 && count >= maxUsages) { break; } } offsetRef[0] = offset; return count; }
// returns number of hits static int processUsagesInFile( @NotNull final PsiFile psiFile, @NotNull final FindModel findModel, @NotNull final Processor<UsageInfo> consumer) { if (findModel.getStringToFind().isEmpty()) { if (!ApplicationManager.getApplication() .runReadAction((Computable<Boolean>) () -> consumer.process(new UsageInfo(psiFile)))) { throw new ProcessCanceledException(); } return 1; } final VirtualFile virtualFile = psiFile.getVirtualFile(); if (virtualFile == null) return 0; if (virtualFile.getFileType().isBinary()) return 0; // do not decompile .class files final Document document = ApplicationManager.getApplication() .runReadAction( (Computable<Document>) () -> virtualFile.isValid() ? FileDocumentManager.getInstance().getDocument(virtualFile) : null); if (document == null) return 0; final int[] offset = {0}; int count = 0; int found; ProgressIndicator indicator = ProgressWrapper.unwrap(ProgressManager.getInstance().getProgressIndicator()); TooManyUsagesStatus tooManyUsagesStatus = TooManyUsagesStatus.getFrom(indicator); do { tooManyUsagesStatus.pauseProcessingIfTooManyUsages(); // wait for user out of read action found = ApplicationManager.getApplication() .runReadAction( (Computable<Integer>) () -> { if (!psiFile.isValid()) return 0; return addToUsages( document, consumer, findModel, psiFile, offset, USAGES_PER_READ_ACTION); }); count += found; } while (found != 0); return count; }
private static List<PsiElement> getTopLevelRegExpChars(String regExpText, Project project) { @SuppressWarnings("deprecation") PsiFile file = PsiFileFactory.getInstance(project).createFileFromText("A.regexp", regExpText); List<PsiElement> result = null; final PsiElement[] children = file.getChildren(); for (PsiElement child : children) { PsiElement[] grandChildren = child.getChildren(); if (grandChildren.length != 1) return Collections .emptyList(); // a | b, more than one branch, can not predict in current way for (PsiElement grandGrandChild : grandChildren[0].getChildren()) { if (result == null) result = new ArrayList<>(); result.add(grandGrandChild); } } return result != null ? result : Collections.<PsiElement>emptyList(); }
@NotNull private Set<PsiFile> getFilesForFastWordSearch() { String stringToFind = myFindModel.getStringToFind(); if (stringToFind.isEmpty() || DumbService.getInstance(myProject).isDumb()) { return Collections.emptySet(); } SearchScope customScope = myFindModel.getCustomScope(); GlobalSearchScope scope = myPsiDirectory != null ? GlobalSearchScopesCore.directoryScope(myPsiDirectory, true) : myModule != null ? myModule.getModuleContentScope() : customScope instanceof GlobalSearchScope ? (GlobalSearchScope) customScope : toGlobal(customScope); if (scope == null) { scope = ProjectScope.getContentScope(myProject); } final Set<PsiFile> resultFiles = new LinkedHashSet<PsiFile>(); if (TrigramIndex.ENABLED) { final Set<Integer> keys = ContainerUtil.newTroveSet(); TrigramBuilder.processTrigrams( stringToFind, new TrigramBuilder.TrigramProcessor() { @Override public boolean execute(int value) { keys.add(value); return true; } }); if (!keys.isEmpty()) { final List<VirtualFile> hits = new ArrayList<VirtualFile>(); final GlobalSearchScope finalScope = scope; ApplicationManager.getApplication() .runReadAction( new Runnable() { @Override public void run() { FileBasedIndex.getInstance() .getFilesWithKey( TrigramIndex.INDEX_ID, keys, new CommonProcessors.CollectProcessor<VirtualFile>(hits), finalScope); } }); for (VirtualFile hit : hits) { if (myFileMask.value(hit)) { PsiFile file = findFile(hit); if (file != null) { resultFiles.add(file); } } } return resultFiles; } } PsiSearchHelperImpl helper = (PsiSearchHelperImpl) PsiSearchHelper.SERVICE.getInstance(myProject); helper.processFilesWithText( scope, UsageSearchContext.ANY, myFindModel.isCaseSensitive(), stringToFind, new Processor<VirtualFile>() { @Override public boolean process(VirtualFile file) { if (myFileMask.value(file)) { ContainerUtil.addIfNotNull(resultFiles, findFile(file)); } return true; } }); // in case our word splitting is incorrect CacheManager cacheManager = CacheManager.SERVICE.getInstance(myProject); PsiFile[] filesWithWord = cacheManager.getFilesWithWord( stringToFind, UsageSearchContext.ANY, scope, myFindModel.isCaseSensitive()); for (PsiFile file : filesWithWord) { if (myFileMask.value(file.getVirtualFile())) { resultFiles.add(file); } } return resultFiles; }
private void searchInFiles( @NotNull Collection<PsiFile> psiFiles, @NotNull FindUsagesProcessPresentation processPresentation, @NotNull final Processor<UsageInfo> consumer) { int i = 0; long totalFilesSize = 0; int count = 0; for (final PsiFile psiFile : psiFiles) { final VirtualFile virtualFile = psiFile.getVirtualFile(); final int index = i++; if (virtualFile == null) continue; long fileLength = UsageViewManagerImpl.getFileLength(virtualFile); if (fileLength == -1) continue; // Binary or invalid final boolean skipProjectFile = ProjectCoreUtil.isProjectOrWorkspaceFile(virtualFile) && !myFindModel.isSearchInProjectFiles(); if (skipProjectFile && !Registry.is("find.search.in.project.files")) continue; if (fileLength > SINGLE_FILE_SIZE_LIMIT) { myLargeFiles.add(psiFile); continue; } myProgress.checkCanceled(); myProgress.setFraction((double) index / psiFiles.size()); String text = FindBundle.message( "find.searching.for.string.in.file.progress", myFindModel.getStringToFind(), virtualFile.getPresentableUrl()); myProgress.setText(text); myProgress.setText2( FindBundle.message("find.searching.for.string.in.file.occurrences.progress", count)); int countInFile = FindInProjectUtil.processUsagesInFile( psiFile, myFindModel, new Processor<UsageInfo>() { @Override public boolean process(UsageInfo info) { return skipProjectFile || consumer.process(info); } }); if (countInFile > 0 && skipProjectFile) { processPresentation.projectFileUsagesFound( new Runnable() { @Override public void run() { FindModel model = myFindModel.clone(); model.setSearchInProjectFiles(true); FindInProjectManager.getInstance(myProject).startFindInProject(model); } }); continue; } count += countInFile; if (countInFile > 0) { totalFilesSize += fileLength; if (totalFilesSize > FILES_SIZE_LIMIT && !myWarningShown) { myWarningShown = true; String message = FindBundle.message( "find.excessive.total.size.prompt", UsageViewManagerImpl.presentableSize(totalFilesSize), ApplicationNamesInfo.getInstance().getProductName()); UsageLimitUtil.showAndCancelIfAborted( myProject, message, processPresentation.getUsageViewPresentation()); } } } }