summaryrefslogtreecommitdiff
path: root/platform/usageView/src/com/intellij
diff options
context:
space:
mode:
Diffstat (limited to 'platform/usageView/src/com/intellij')
-rw-r--r--platform/usageView/src/com/intellij/usages/ChunkExtractor.java84
-rw-r--r--platform/usageView/src/com/intellij/usages/FindUsagesProcessPresentation.java11
-rw-r--r--platform/usageView/src/com/intellij/usages/TextChunk.java12
-rw-r--r--platform/usageView/src/com/intellij/usages/UsageInfo2UsageAdapter.java51
-rw-r--r--platform/usageView/src/com/intellij/usages/impl/SearchForUsagesRunnable.java64
-rw-r--r--platform/usageView/src/com/intellij/usages/impl/SyntaxHighlighterOverEditorHighlighter.java108
-rw-r--r--platform/usageView/src/com/intellij/usages/impl/UsageViewManagerImpl.java42
-rw-r--r--platform/usageView/src/com/intellij/usages/impl/rules/UsageTypeGroupingRule.java9
8 files changed, 318 insertions, 63 deletions
diff --git a/platform/usageView/src/com/intellij/usages/ChunkExtractor.java b/platform/usageView/src/com/intellij/usages/ChunkExtractor.java
index 930321fc61d5..dbbaeb48b72f 100644
--- a/platform/usageView/src/com/intellij/usages/ChunkExtractor.java
+++ b/platform/usageView/src/com/intellij/usages/ChunkExtractor.java
@@ -19,9 +19,7 @@ import com.intellij.injected.editor.DocumentWindow;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.lexer.Lexer;
import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.editor.HighlighterColors;
-import com.intellij.openapi.editor.RangeMarker;
+import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.editor.markup.TextAttributes;
@@ -39,11 +37,14 @@ import com.intellij.psi.tree.IElementType;
import com.intellij.reference.SoftReference;
import com.intellij.usageView.UsageTreeColors;
import com.intellij.usageView.UsageTreeColorsScheme;
+import com.intellij.usages.impl.SyntaxHighlighterOverEditorHighlighter;
+import com.intellij.usages.impl.rules.UsageType;
import com.intellij.util.Processor;
import com.intellij.util.containers.FactoryMap;
import com.intellij.util.text.CharArrayUtil;
import com.intellij.util.text.StringFactory;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.lang.ref.WeakReference;
@@ -64,9 +65,7 @@ public class ChunkExtractor {
private final Document myDocument;
private long myDocumentStamp;
- private final SyntaxHighlighter myHighlighter;
-
- private final Lexer myLexer;
+ private final SyntaxHighlighterOverEditorHighlighter myHighlighter;
private abstract static class WeakFactory<T> {
private WeakReference<T> myRef;
@@ -119,11 +118,10 @@ public class ChunkExtractor {
myDocument = PsiDocumentManager.getInstance(project).getDocument(file);
LOG.assertTrue(myDocument != null);
final FileType fileType = file.getFileType();
- final SyntaxHighlighter highlighter = SyntaxHighlighterFactory.getSyntaxHighlighter(fileType, project, file.getVirtualFile());
- myHighlighter = highlighter == null ? new PlainSyntaxHighlighter() : highlighter;
- myLexer = myHighlighter.getHighlightingLexer();
- myLexer.start(myDocument.getCharsSequence());
- myDocumentStamp = myDocument.getModificationStamp();
+ SyntaxHighlighter highlighter = SyntaxHighlighterFactory.getSyntaxHighlighter(fileType, project, file.getVirtualFile());
+ highlighter = highlighter == null ? new PlainSyntaxHighlighter() : highlighter;
+ myHighlighter = new SyntaxHighlighterOverEditorHighlighter(highlighter, file.getVirtualFile(), project);
+ myDocumentStamp = -1;
}
public static int getStartOffset(final List<RangeMarker> rangeMarkers) {
@@ -194,18 +192,21 @@ public class ChunkExtractor {
int end,
boolean selectUsageWithBold,
@NotNull List<TextChunk> result) {
- final Lexer lexer = myLexer;
- final SyntaxHighlighter highlighter = myHighlighter;
+ final Lexer lexer = myHighlighter.getHighlightingLexer();
+ final SyntaxHighlighterOverEditorHighlighter highlighter = myHighlighter;
LOG.assertTrue(start <= end);
int i = StringUtil.indexOf(chars, '\n', start, end);
if (i != -1) end = i;
- if (lexer.getTokenStart() > start || myDocumentStamp != myDocument.getModificationStamp()) {
- lexer.start(chars);
+ if (myDocumentStamp != myDocument.getModificationStamp()) {
+ highlighter.restart(chars);
myDocumentStamp = myDocument.getModificationStamp();
+ } else if(lexer.getTokenStart() > start) {
+ highlighter.resetPosition(0); // todo restart from nearest position with initial state
}
+
boolean isBeginning = true;
for(;lexer.getTokenType() != null; lexer.advance()) {
@@ -218,8 +219,10 @@ public class ChunkExtractor {
hiEnd = Math.min(hiEnd, end);
if (hiStart >= hiEnd) { continue; }
- String text = chars.subSequence(hiStart, hiEnd).toString();
- if (isBeginning && text.trim().isEmpty()) continue;
+ if (isBeginning) {
+ String text = chars.subSequence(hiStart, hiEnd).toString();
+ if(text.trim().isEmpty()) continue;
+ }
isBeginning = false;
IElementType tokenType = lexer.getTokenType();
TextAttributesKey[] tokenHighlights = highlighter.getTokenHighlights(tokenType);
@@ -234,7 +237,7 @@ public class ChunkExtractor {
@NotNull final CharSequence chars,
int hiStart,
final int hiEnd,
- @NotNull TextAttributesKey[] tokenHighlights,
+ @NotNull final TextAttributesKey[] tokenHighlights,
final boolean selectUsageWithBold,
@NotNull final List<TextChunk> result) {
final TextAttributes originalAttrs = convertAttributes(tokenHighlights);
@@ -249,8 +252,12 @@ public class ChunkExtractor {
int usageStart = segment.getStartOffset();
int usageEnd = segment.getEndOffset();
if (rangeIntersect(lastOffset[0], hiEnd, usageStart, usageEnd)) {
- addChunk(chars, lastOffset[0], Math.max(lastOffset[0], usageStart), originalAttrs, false, result);
- addChunk(chars, Math.max(lastOffset[0], usageStart), Math.min(hiEnd, usageEnd), originalAttrs, selectUsageWithBold, result);
+ addChunk(chars, lastOffset[0], Math.max(lastOffset[0], usageStart), originalAttrs, false, null, result);
+
+ UsageType usageType = isHighlightedAsString(tokenHighlights)
+ ? UsageType.LITERAL_USAGE
+ : isHighlightedAsComment(tokenHighlights) ? UsageType.COMMENT_USAGE : null;
+ addChunk(chars, Math.max(lastOffset[0], usageStart), Math.min(hiEnd, usageEnd), originalAttrs, selectUsageWithBold, usageType, result);
lastOffset[0] = usageEnd;
if (usageEnd > hiEnd) {
return false;
@@ -260,8 +267,40 @@ public class ChunkExtractor {
}
});
if (lastOffset[0] < hiEnd) {
- addChunk(chars, lastOffset[0], hiEnd, originalAttrs, false, result);
+ addChunk(chars, lastOffset[0], hiEnd, originalAttrs, false, null, result);
+ }
+ }
+
+ public static boolean isHighlightedAsComment(TextAttributesKey... keys) {
+ for (TextAttributesKey key : keys) {
+ if (key == DefaultLanguageHighlighterColors.DOC_COMMENT ||
+ key == SyntaxHighlighterColors.DOC_COMMENT ||
+ key == DefaultLanguageHighlighterColors.LINE_COMMENT ||
+ key == SyntaxHighlighterColors.LINE_COMMENT ||
+ key == DefaultLanguageHighlighterColors.BLOCK_COMMENT ||
+ key == SyntaxHighlighterColors.JAVA_BLOCK_COMMENT
+ ) {
+ return true;
+ }
+ final TextAttributesKey fallbackAttributeKey = key.getFallbackAttributeKey();
+ if (fallbackAttributeKey != null && isHighlightedAsComment(fallbackAttributeKey)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static boolean isHighlightedAsString(TextAttributesKey... keys) {
+ for (TextAttributesKey key : keys) {
+ if (key == DefaultLanguageHighlighterColors.STRING || key == SyntaxHighlighterColors.STRING) {
+ return true;
+ }
+ final TextAttributesKey fallbackAttributeKey = key.getFallbackAttributeKey();
+ if (fallbackAttributeKey != null && isHighlightedAsString(fallbackAttributeKey)) {
+ return true;
+ }
}
+ return false;
}
private static void addChunk(@NotNull CharSequence chars,
@@ -269,13 +308,14 @@ public class ChunkExtractor {
int end,
@NotNull TextAttributes originalAttrs,
boolean bold,
+ @Nullable UsageType usageType,
@NotNull List<TextChunk> result) {
if (start >= end) return;
TextAttributes attrs = bold
? TextAttributes.merge(originalAttrs, new TextAttributes(null, null, null, null, Font.BOLD))
: originalAttrs;
- result.add(new TextChunk(attrs, StringFactory.createShared(CharArrayUtil.fromSequence(chars, start, end))));
+ result.add(new TextChunk(attrs, StringFactory.createShared(CharArrayUtil.fromSequence(chars, start, end)), usageType));
}
private static boolean rangeIntersect(int s1, int e1, int s2, int e2) {
diff --git a/platform/usageView/src/com/intellij/usages/FindUsagesProcessPresentation.java b/platform/usageView/src/com/intellij/usages/FindUsagesProcessPresentation.java
index d608303eec09..2248182a3c5c 100644
--- a/platform/usageView/src/com/intellij/usages/FindUsagesProcessPresentation.java
+++ b/platform/usageView/src/com/intellij/usages/FindUsagesProcessPresentation.java
@@ -20,6 +20,7 @@ import com.intellij.openapi.util.Factory;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.ArrayList;
@@ -41,6 +42,7 @@ public class FindUsagesProcessPresentation {
private Factory<ProgressIndicator> myProgressIndicatorFactory;
private Collection<PsiFile> myLargeFiles;
private boolean myShowFindOptionsPrompt = true;
+ private Runnable mySearchWithProjectFiles;
public FindUsagesProcessPresentation(@NotNull UsageViewPresentation presentation) {
myUsageViewPresentation = presentation;
@@ -80,6 +82,15 @@ public class FindUsagesProcessPresentation {
myProgressIndicatorFactory = progressIndicatorFactory;
}
+ @Nullable
+ public Runnable searchIncludingProjectFileUsages() {
+ return mySearchWithProjectFiles;
+ }
+
+ public void projectFileUsagesFound(@NotNull Runnable searchWithProjectFiles) {
+ mySearchWithProjectFiles = searchWithProjectFiles;
+ }
+
public void setLargeFilesWereNotScanned(@NotNull Collection<PsiFile> largeFiles) {
myLargeFiles = largeFiles;
}
diff --git a/platform/usageView/src/com/intellij/usages/TextChunk.java b/platform/usageView/src/com/intellij/usages/TextChunk.java
index e1c3345d41da..e74debdb97fb 100644
--- a/platform/usageView/src/com/intellij/usages/TextChunk.java
+++ b/platform/usageView/src/com/intellij/usages/TextChunk.java
@@ -18,17 +18,25 @@ package com.intellij.usages;
import com.intellij.openapi.editor.markup.AttributesFlyweight;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.ui.SimpleTextAttributes;
+import com.intellij.usages.impl.rules.UsageType;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
public class TextChunk {
public static final TextChunk[] EMPTY_ARRAY = new TextChunk[0];
private final AttributesFlyweight myAttributes;
private final String myText;
+ private final UsageType myType;
public TextChunk(@NotNull TextAttributes attributes, @NotNull String text) {
+ this(attributes, text, null);
+ }
+
+ public TextChunk(@NotNull TextAttributes attributes, @NotNull String text, @Nullable UsageType type) {
myAttributes = attributes.getFlyweight();
myText = text;
+ myType = type;
}
@NotNull
@@ -45,6 +53,10 @@ public class TextChunk {
return getText();
}
+ public @Nullable UsageType getType() {
+ return myType;
+ }
+
@NotNull
public SimpleTextAttributes getSimpleAttributesIgnoreBackground() {
SimpleTextAttributes simples = SimpleTextAttributes.fromTextAttributes(getAttributes());
diff --git a/platform/usageView/src/com/intellij/usages/UsageInfo2UsageAdapter.java b/platform/usageView/src/com/intellij/usages/UsageInfo2UsageAdapter.java
index aaccbfffbe18..418890ce17d9 100644
--- a/platform/usageView/src/com/intellij/usages/UsageInfo2UsageAdapter.java
+++ b/platform/usageView/src/com/intellij/usages/UsageInfo2UsageAdapter.java
@@ -38,11 +38,9 @@ import com.intellij.reference.SoftReference;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.usageView.UsageInfo;
import com.intellij.usageView.UsageViewBundle;
+import com.intellij.usages.impl.rules.UsageType;
import com.intellij.usages.rules.*;
-import com.intellij.util.ArrayUtil;
-import com.intellij.util.IncorrectOperationException;
-import com.intellij.util.NotNullFunction;
-import com.intellij.util.Processor;
+import com.intellij.util.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -79,7 +77,8 @@ public class UsageInfo2UsageAdapter implements UsageInModule,
private final int myLineNumber;
private final int myOffset;
protected Icon myIcon;
- private Reference<TextChunk[]> myTextChunks; // allow to be gced and recreated on-demand because it requires a lot of memory
+ private volatile Reference<TextChunk[]> myTextChunks; // allow to be gced and recreated on-demand because it requires a lot of memory
+ private volatile UsageType myUsageType;
public UsageInfo2UsageAdapter(@NotNull final UsageInfo usageInfo) {
myUsageInfo = usageInfo;
@@ -336,7 +335,7 @@ public class UsageInfo2UsageAdapter implements UsageInModule,
UsageInfo[] merged = ArrayUtil.mergeArrays(getMergedInfos(), u2.getMergedInfos());
myMergedUsageInfos = merged.length == 1 ? merged[0] : merged;
Arrays.sort(getMergedInfos(), BY_NAVIGATION_OFFSET);
- initChunks();
+ myTextChunks = null; // chunks will be rebuilt lazily (IDEA-126048)
return true;
}
@@ -493,4 +492,44 @@ public class UsageInfo2UsageAdapter implements UsageInModule,
public String getTooltipText() {
return myUsageInfo.getTooltipText();
}
+
+ public @Nullable UsageType getUsageType() {
+ UsageType usageType = myUsageType;
+
+ if (usageType == null) {
+ usageType = UsageType.UNCLASSIFIED;
+ PsiFile file = getPsiFile();
+
+ if (file != null) {
+ ChunkExtractor extractor = ChunkExtractor.getExtractor(file);
+ Segment segment = getFirstSegment();
+
+ if (segment != null) {
+ Document document = PsiDocumentManager.getInstance(getProject()).getDocument(file);
+
+ if (document != null) {
+ SmartList<TextChunk> chunks = new SmartList<TextChunk>();
+ extractor.createTextChunks(
+ this,
+ document.getCharsSequence(),
+ segment.getStartOffset(),
+ segment.getEndOffset(),
+ false,
+ chunks
+ );
+
+ for(TextChunk chunk:chunks) {
+ UsageType chunkUsageType = chunk.getType();
+ if (chunkUsageType != null) {
+ usageType = chunkUsageType;
+ break;
+ }
+ }
+ }
+ }
+ }
+ myUsageType = usageType;
+ }
+ return usageType;
+ }
}
diff --git a/platform/usageView/src/com/intellij/usages/impl/SearchForUsagesRunnable.java b/platform/usageView/src/com/intellij/usages/impl/SearchForUsagesRunnable.java
index 8b065b30d167..170d1802eee4 100644
--- a/platform/usageView/src/com/intellij/usages/impl/SearchForUsagesRunnable.java
+++ b/platform/usageView/src/com/intellij/usages/impl/SearchForUsagesRunnable.java
@@ -19,6 +19,7 @@ import com.intellij.find.FindManager;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.KeyboardShortcut;
import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.colors.CodeInsightColors;
@@ -71,6 +72,7 @@ class SearchForUsagesRunnable implements Runnable {
@NonNls private static final String FIND_OPTIONS_HREF_TARGET = "FindOptions";
@NonNls private static final String SEARCH_IN_PROJECT_HREF_TARGET = "SearchInProject";
@NonNls private static final String LARGE_FILES_HREF_TARGET = "LargeFiles";
+ @NonNls private static final String SHOW_PROJECT_FILE_OCCURRENCES_HREF_TARGET = "SHOW_PROJECT_FILE_OCCURRENCES";
private final AtomicInteger myUsageCountWithoutDefinition = new AtomicInteger(0);
private final AtomicReference<Usage> myFirstUsage = new AtomicReference<Usage>();
@NotNull
@@ -80,7 +82,7 @@ class SearchForUsagesRunnable implements Runnable {
private final UsageTarget[] mySearchFor;
private final Factory<UsageSearcher> mySearcherFactory;
private final FindUsagesProcessPresentation myProcessPresentation;
- @NotNull private final SearchScope mySearchScope;
+ @NotNull private final SearchScope mySearchScopeToWarnOfFallingOutOf;
private final UsageViewManager.UsageViewStateListener myListener;
private final UsageViewManagerImpl myUsageViewManager;
private final AtomicInteger myOutOfScopeUsages = new AtomicInteger();
@@ -92,7 +94,7 @@ class SearchForUsagesRunnable implements Runnable {
@NotNull UsageTarget[] searchFor,
@NotNull Factory<UsageSearcher> searcherFactory,
@NotNull FindUsagesProcessPresentation processPresentation,
- @NotNull SearchScope scope,
+ @NotNull SearchScope searchScopeToWarnOfFallingOutOf,
@Nullable UsageViewManager.UsageViewStateListener listener) {
myProject = project;
myUsageViewRef = usageViewRef;
@@ -100,7 +102,7 @@ class SearchForUsagesRunnable implements Runnable {
mySearchFor = searchFor;
mySearcherFactory = searcherFactory;
myProcessPresentation = processPresentation;
- mySearchScope = scope;
+ mySearchScopeToWarnOfFallingOutOf = searchScopeToWarnOfFallingOutOf;
myListener = listener;
myUsageViewManager = usageViewManager;
}
@@ -135,25 +137,43 @@ class SearchForUsagesRunnable implements Runnable {
+ UsageViewBundle.message("large.files.were.ignored", largeFiles.size()) + "</a>)";
resultLines.add(shortMessage);
- resultListener = new HyperlinkAdapter(){
- @Override
- protected void hyperlinkActivated(HyperlinkEvent e) {
- if (e.getDescription().equals(LARGE_FILES_HREF_TARGET)) {
- String detailedMessage = detailedLargeFilesMessage(largeFiles);
- List<String> strings = new ArrayList<String>(lines);
- strings.add(detailedMessage);
- ToolWindowManager.getInstance(project).notifyByBalloon(ToolWindowId.FIND, info, wrapInHtml(strings), AllIcons.Actions.Find, listener);
- }
- else if (listener != null) {
- listener.hyperlinkUpdate(e);
- }
+ resultListener = addHrefHandling(resultListener, LARGE_FILES_HREF_TARGET, new Runnable() {
+ public void run() {
+ String detailedMessage = detailedLargeFilesMessage(largeFiles);
+ List<String> strings = new ArrayList<String>(lines);
+ strings.add(detailedMessage);
+ //noinspection SSBasedInspection
+ ToolWindowManager.getInstance(project).notifyByBalloon(ToolWindowId.FIND, info, wrapInHtml(strings), AllIcons.Actions.Find, listener);
}
- };
+ });
}
+ Runnable searchIncludingProjectFileUsages = processPresentation.searchIncludingProjectFileUsages();
+ if (searchIncludingProjectFileUsages != null) {
+ resultLines.add("Occurrences in " + ApplicationNamesInfo.getInstance().getProductName() + " project files are skipped. " +
+ "<a href='" + SHOW_PROJECT_FILE_OCCURRENCES_HREF_TARGET + "'>Include them</a>");
+ resultListener = addHrefHandling(resultListener, SHOW_PROJECT_FILE_OCCURRENCES_HREF_TARGET, searchIncludingProjectFileUsages);
+ }
+
+ //noinspection SSBasedInspection
ToolWindowManager.getInstance(project).notifyByBalloon(ToolWindowId.FIND, info, wrapInHtml(resultLines), AllIcons.Actions.Find, resultListener);
}
+ private static HyperlinkListener addHrefHandling(@Nullable final HyperlinkListener listener,
+ @NotNull final String hrefTarget, @NotNull final Runnable handler) {
+ return new HyperlinkAdapter() {
+ @Override
+ protected void hyperlinkActivated(HyperlinkEvent e) {
+ if (e.getDescription().equals(hrefTarget)) {
+ handler.run();
+ }
+ else if (listener != null) {
+ listener.hyperlinkUpdate(e);
+ }
+ }
+ };
+ }
+
@NotNull
private static String wrapInHtml(@NotNull List<String> strings) {
return XmlStringUtil.wrapInHtml(StringUtil.join(strings, "<br>"));
@@ -319,7 +339,7 @@ class SearchForUsagesRunnable implements Runnable {
ProgressIndicator indicator = ProgressWrapper.unwrap(ProgressManager.getInstance().getProgressIndicator());
if (indicator != null && indicator.isCanceled()) return false;
- if (!UsageViewManagerImpl.isInScope(usage, mySearchScope)) {
+ if (!UsageViewManagerImpl.isInScope(usage, mySearchScopeToWarnOfFallingOutOf)) {
myOutOfScopeUsages.incrementAndGet();
return true;
}
@@ -389,7 +409,7 @@ class SearchForUsagesRunnable implements Runnable {
List<String> lines = new ArrayList<String>();
lines.add(StringUtil.escapeXml(message));
if (myOutOfScopeUsages.get() != 0) {
- lines.add(UsageViewManagerImpl.outOfScopeMessage(myOutOfScopeUsages.get(), mySearchScope));
+ lines.add(UsageViewManagerImpl.outOfScopeMessage(myOutOfScopeUsages.get(), mySearchScopeToWarnOfFallingOutOf));
}
if (myProcessPresentation.isShowFindOptionsPrompt()) {
lines.add(createOptionsHtml(mySearchFor));
@@ -432,7 +452,7 @@ class SearchForUsagesRunnable implements Runnable {
lines.add("Only one usage found.");
if (myOutOfScopeUsages.get() != 0) {
- lines.add(UsageViewManagerImpl.outOfScopeMessage(myOutOfScopeUsages.get(), mySearchScope));
+ lines.add(UsageViewManagerImpl.outOfScopeMessage(myOutOfScopeUsages.get(), mySearchScopeToWarnOfFallingOutOf));
}
lines.add(createOptionsHtml(mySearchFor));
MessageType type = myOutOfScopeUsages.get() == 0 ? MessageType.INFO : MessageType.WARNING;
@@ -456,11 +476,13 @@ class SearchForUsagesRunnable implements Runnable {
hyperlinkListener = null;
}
else {
- lines = Arrays.asList(UsageViewManagerImpl.outOfScopeMessage(myOutOfScopeUsages.get(), mySearchScope), createSearchInProjectHtml());
+ lines = Arrays.asList(UsageViewManagerImpl.outOfScopeMessage(myOutOfScopeUsages.get(), mySearchScopeToWarnOfFallingOutOf), createSearchInProjectHtml());
hyperlinkListener = createSearchInProjectListener();
}
- if (!myProcessPresentation.getLargeFiles().isEmpty() || myOutOfScopeUsages.get() != 0) {
+ if (!myProcessPresentation.getLargeFiles().isEmpty() ||
+ myOutOfScopeUsages.get() != 0 ||
+ myProcessPresentation.searchIncludingProjectFileUsages() != null) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
diff --git a/platform/usageView/src/com/intellij/usages/impl/SyntaxHighlighterOverEditorHighlighter.java b/platform/usageView/src/com/intellij/usages/impl/SyntaxHighlighterOverEditorHighlighter.java
new file mode 100644
index 000000000000..04690cc6fa20
--- /dev/null
+++ b/platform/usageView/src/com/intellij/usages/impl/SyntaxHighlighterOverEditorHighlighter.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2000-2014 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.usages.impl;
+
+import com.intellij.lexer.LayeredLexer;
+import com.intellij.lexer.Lexer;
+import com.intellij.openapi.editor.colors.TextAttributesKey;
+import com.intellij.openapi.editor.ex.util.LayeredHighlighterIterator;
+import com.intellij.openapi.editor.ex.util.LayeredLexerEditorHighlighter;
+import com.intellij.openapi.editor.highlighter.EditorHighlighter;
+import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory;
+import com.intellij.openapi.editor.highlighter.HighlighterIterator;
+import com.intellij.openapi.fileTypes.PlainSyntaxHighlighter;
+import com.intellij.openapi.fileTypes.PlainTextFileType;
+import com.intellij.openapi.fileTypes.SyntaxHighlighter;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.impl.search.LexerEditorHighlighterLexer;
+import com.intellij.psi.tree.IElementType;
+import org.jetbrains.annotations.NotNull;
+
+/**
+* Created by Maxim.Mossienko on 7/31/2014.
+*/
+public class SyntaxHighlighterOverEditorHighlighter implements SyntaxHighlighter {
+ private final Lexer lexer;
+ private LayeredHighlighterIterator layeredHighlighterIterator = null;
+ private final SyntaxHighlighter highlighter;
+
+ public SyntaxHighlighterOverEditorHighlighter(SyntaxHighlighter _highlighter, VirtualFile file, Project project) {
+ if (file.getFileType() == PlainTextFileType.INSTANCE) { // optimization for large files, PlainTextSyntaxHighlighterFactory is slow
+ highlighter = new PlainSyntaxHighlighter();
+ lexer = highlighter.getHighlightingLexer();
+ } else {
+ highlighter = _highlighter;
+ LayeredLexer.ourDisableLayersFlag.set(Boolean.TRUE);
+ EditorHighlighter editorHighlighter = EditorHighlighterFactory.getInstance().createEditorHighlighter(project, file);
+
+ try {
+ if (editorHighlighter instanceof LayeredLexerEditorHighlighter) {
+ lexer = new LexerEditorHighlighterLexer(editorHighlighter, false);
+ }
+ else {
+ lexer = highlighter.getHighlightingLexer();
+ }
+ }
+ finally {
+ LayeredLexer.ourDisableLayersFlag.set(null);
+ }
+ }
+ }
+
+ @NotNull
+ @Override
+ public Lexer getHighlightingLexer() {
+ return lexer;
+ }
+
+ @NotNull
+ @Override
+ public TextAttributesKey[] getTokenHighlights(IElementType tokenType) {
+ final SyntaxHighlighter activeSyntaxHighlighter =
+ layeredHighlighterIterator != null ? layeredHighlighterIterator.getActiveSyntaxHighlighter() : highlighter;
+ return activeSyntaxHighlighter.getTokenHighlights(tokenType);
+ }
+
+ public void restart(@NotNull CharSequence text) {
+ lexer.start(text);
+
+ if (lexer instanceof LexerEditorHighlighterLexer) {
+ HighlighterIterator iterator = ((LexerEditorHighlighterLexer)lexer).getHighlighterIterator();
+ if (iterator instanceof LayeredHighlighterIterator) {
+ layeredHighlighterIterator = (LayeredHighlighterIterator)iterator;
+ } else {
+ layeredHighlighterIterator = null;
+ }
+ }
+ }
+
+ public void resetPosition(int startOffset) {
+ if (lexer instanceof LexerEditorHighlighterLexer) {
+ ((LexerEditorHighlighterLexer)lexer).resetPosition(startOffset);
+
+ HighlighterIterator iterator = ((LexerEditorHighlighterLexer)lexer).getHighlighterIterator();
+ if (iterator instanceof LayeredHighlighterIterator) {
+ layeredHighlighterIterator = (LayeredHighlighterIterator)iterator;
+ } else {
+ layeredHighlighterIterator = null;
+ }
+ } else {
+ CharSequence text = lexer.getBufferSequence();
+ lexer.start(text, startOffset, text.length());
+ }
+ }
+}
diff --git a/platform/usageView/src/com/intellij/usages/impl/UsageViewManagerImpl.java b/platform/usageView/src/com/intellij/usages/impl/UsageViewManagerImpl.java
index 6d7ce9c07a14..b9fc77295d62 100644
--- a/platform/usageView/src/com/intellij/usages/impl/UsageViewManagerImpl.java
+++ b/platform/usageView/src/com/intellij/usages/impl/UsageViewManagerImpl.java
@@ -33,9 +33,8 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowId;
import com.intellij.openapi.wm.ToolWindowManager;
-import com.intellij.psi.search.GlobalSearchScope;
-import com.intellij.psi.search.LocalSearchScope;
-import com.intellij.psi.search.SearchScope;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.search.*;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.content.Content;
import com.intellij.usageView.UsageViewBundle;
@@ -122,23 +121,23 @@ public class UsageViewManagerImpl extends UsageViewManager {
@NotNull final UsageViewPresentation presentation,
@NotNull final FindUsagesProcessPresentation processPresentation,
@Nullable final UsageViewStateListener listener) {
- final SearchScope searchScope = getSearchScope(searchFor);
+ final SearchScope searchScope = getMaxSearchScopeToWarnOfFallingOutOf(searchFor);
return doSearchAndShow(searchFor, searcherFactory, presentation, processPresentation, listener, searchScope);
}
- UsageView doSearchAndShow(@NotNull final UsageTarget[] searchFor,
+ private UsageView doSearchAndShow(@NotNull final UsageTarget[] searchFor,
@NotNull final Factory<UsageSearcher> searcherFactory,
@NotNull final UsageViewPresentation presentation,
@NotNull final FindUsagesProcessPresentation processPresentation,
@Nullable final UsageViewStateListener listener,
- @NotNull final SearchScope searchScope) {
+ @NotNull final SearchScope searchScopeToWarnOfFallingOutOf) {
final AtomicReference<UsageViewImpl> usageViewRef = new AtomicReference<UsageViewImpl>();
Task.Backgroundable task = new Task.Backgroundable(myProject, getProgressTitle(presentation), true, new SearchInBackgroundOption()) {
@Override
public void run(@NotNull final ProgressIndicator indicator) {
new SearchForUsagesRunnable(UsageViewManagerImpl.this, UsageViewManagerImpl.this.myProject, usageViewRef, presentation, searchFor, searcherFactory,
- processPresentation, searchScope, listener).run();
+ processPresentation, searchScopeToWarnOfFallingOutOf, listener).run();
}
@NotNull
@@ -159,7 +158,7 @@ public class UsageViewManagerImpl extends UsageViewManager {
}
@NotNull
- private SearchScope getSearchScope(@NotNull UsageTarget[] searchFor) {
+ private SearchScope getMaxSearchScopeToWarnOfFallingOutOf(@NotNull UsageTarget[] searchFor) {
UsageTarget target = searchFor[0];
if (target instanceof TypeSafeDataProvider) {
final SearchScope[] scope = new SearchScope[1];
@@ -171,7 +170,7 @@ public class UsageViewManagerImpl extends UsageViewManager {
});
return scope[0];
}
- return GlobalSearchScope.projectScope(myProject);
+ return GlobalSearchScope.allScope(myProject); // by default do not warn of falling out of scope
}
@Override
@@ -262,10 +261,27 @@ public class UsageViewManagerImpl extends UsageViewManager {
}
public static boolean isInScope(@NotNull Usage usage, @NotNull SearchScope searchScope) {
- VirtualFile file = usage instanceof UsageInFile ? ((UsageInFile)usage).getFile() : usage instanceof PsiElementUsage ? PsiUtilCore
- .getVirtualFile(((PsiElementUsage)usage).getElement()) : null;
- return file != null && (searchScope instanceof LocalSearchScope
- ? ((LocalSearchScope)searchScope).isInScope(file) : ((GlobalSearchScope)searchScope).contains(file));
+ PsiElement element = null;
+ VirtualFile file = usage instanceof UsageInFile ? ((UsageInFile)usage).getFile() :
+ usage instanceof PsiElementUsage ? PsiUtilCore.getVirtualFile(element = ((PsiElementUsage)usage).getElement()) : null;
+ if (file != null) {
+ return isFileInScope(file, searchScope);
+ }
+ else if(element != null) {
+ return searchScope instanceof EverythingGlobalScope ||
+ searchScope instanceof ProjectScopeImpl ||
+ searchScope instanceof ProjectAndLibrariesScope;
+ }
+ return false;
+ }
+
+ private static boolean isFileInScope(@NotNull VirtualFile file, @NotNull SearchScope searchScope) {
+ if (searchScope instanceof LocalSearchScope) {
+ return ((LocalSearchScope)searchScope).isInScope(file);
+ }
+ else {
+ return ((GlobalSearchScope)searchScope).contains(file);
+ }
}
@NotNull
diff --git a/platform/usageView/src/com/intellij/usages/impl/rules/UsageTypeGroupingRule.java b/platform/usageView/src/com/intellij/usages/impl/rules/UsageTypeGroupingRule.java
index b182bc31bceb..8d1de0bc06e3 100644
--- a/platform/usageView/src/com/intellij/usages/impl/rules/UsageTypeGroupingRule.java
+++ b/platform/usageView/src/com/intellij/usages/impl/rules/UsageTypeGroupingRule.java
@@ -19,6 +19,7 @@ import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.vcs.FileStatus;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.usages.*;
import com.intellij.usages.rules.PsiElementUsage;
@@ -42,7 +43,13 @@ public class UsageTypeGroupingRule implements UsageGroupingRuleEx {
if (usage instanceof PsiElementUsage) {
PsiElementUsage elementUsage = (PsiElementUsage)usage;
- UsageType usageType = getUsageType(elementUsage.getElement(), targets);
+ PsiElement element = elementUsage.getElement();
+ UsageType usageType = getUsageType(element, targets);
+
+ if (usageType == null && element instanceof PsiFile && elementUsage instanceof UsageInfo2UsageAdapter) {
+ usageType = ((UsageInfo2UsageAdapter)elementUsage).getUsageType();
+ }
+
if (usageType != null) return new UsageTypeGroup(usageType);
if (usage instanceof ReadWriteAccessUsage) {