diff options
Diffstat (limited to 'platform/usageView/src/com/intellij')
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) { |