diff --git a/UsageView/src/com/intellij/usages/ChunkExtractor.java b/UsageView/src/com/intellij/usages/ChunkExtractor.java new file mode 100644 index 000000000000..584cfe7a5328 --- /dev/null +++ b/UsageView/src/com/intellij/usages/ChunkExtractor.java @@ -0,0 +1,178 @@ +/* +* Copyright (c) 2000-2005 by JetBrains s.r.o. All Rights Reserved. +* Use is subject to license terms. +*/ +package com.intellij.usages; + +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.colors.EditorColorsScheme; +import com.intellij.openapi.editor.colors.TextAttributesKey; +import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.fileTypes.SyntaxHighlighter; +import com.intellij.psi.PsiFile; +import com.intellij.psi.tree.IElementType; +import com.intellij.usageView.UsageTreeColors; +import com.intellij.usageView.UsageTreeColorsScheme; +import com.intellij.util.text.CharArrayUtil; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +/** + * @author peter + */ +public class ChunkExtractor { + private static final Logger LOG = Logger.getInstance("#com.intellij.usages.ChunkExtractor"); + private Document myDocument; + private int myLineNumber; + private PsiFile myPsiFile; + private List myRangeMarkers; + private EditorColorsScheme myColorsScheme; + private int myColumnNumber; + + public ChunkExtractor(final Document document, + final int lineNumber, + final PsiFile psiFile, + final List rangeMarkers, + final int columnNumber) { + myDocument = document; + myLineNumber = lineNumber; + myPsiFile = psiFile; + myRangeMarkers = rangeMarkers; + myColumnNumber = columnNumber; + myColorsScheme = UsageTreeColorsScheme.getInstance().getScheme(); + } + + + public TextChunk[] extractChunks() { + int lineStartOffset = myDocument.getLineStartOffset(myLineNumber); + int lineEndOffset = myDocument.getLineEndOffset(myLineNumber); + return createTextChunks(myDocument.getCharsSequence(), myPsiFile.getFileType().getHighlighter(myPsiFile.getProject()), lineStartOffset, lineEndOffset); + } + + private TextChunk[] createTextChunks(final CharSequence chars, + SyntaxHighlighter highlighter, + int start, + int end) { + LOG.assertTrue(start <= end); + List result = new ArrayList(); + + appendPrefix(result); + + Lexer lexer = highlighter.getHighlightingLexer(); + lexer.start(CharArrayUtil.fromSequence(chars)); + + for (int offset = start; offset < end; offset++) { + if (chars.charAt(offset) == '\n') { + end = offset; + break; + } + } + + boolean isBeginning = true; + + while (lexer.getTokenType() != null) { + try { + int hiStart = lexer.getTokenStart(); + int hiEnd = lexer.getTokenEnd(); + + if (hiStart >= end) break; + + hiStart = Math.max(hiStart, start); + hiEnd = Math.min(hiEnd, end); + if (hiStart >= hiEnd) { continue; } + + String text = chars.subSequence(hiStart, hiEnd).toString(); + if (isBeginning && text.trim().length() == 0) continue; + isBeginning = false; + IElementType tokenType = lexer.getTokenType(); + TextAttributesKey[] tokenHighlights = highlighter.getTokenHighlights(tokenType); + + RangeMarker intersectionMarker = getIntersectingMarker(hiStart, hiEnd); + if (intersectionMarker != null) { + processIntersectingRange(chars, hiStart, hiEnd, tokenHighlights, result, intersectionMarker); + } + else { + result.add(new TextChunk(convertAttributes(tokenHighlights), text)); + } + } + finally { + lexer.advance(); + } + } + + return result.toArray(new TextChunk[result.size()]); + } + + private RangeMarker getIntersectingMarker(int hiStart, int hiEnd) { + for (int i = 0; i < myRangeMarkers.size(); i++) { + RangeMarker marker = myRangeMarkers.get(i); + if (marker.isValid() && rangeIntersect(hiStart, hiEnd, marker.getStartOffset(), marker.getEndOffset())) return marker; + } + return null; + } + + private void processIntersectingRange(CharSequence chars, + int hiStart, + int hiEnd, + TextAttributesKey[] tokenHighlights, + List result, + RangeMarker rangeMarker) { + int usageStart = rangeMarker.getStartOffset(); + int usageEnd = rangeMarker.getEndOffset(); + + TextAttributes originalAttrs = convertAttributes(tokenHighlights); + addChunk(chars, hiStart, Math.max(hiStart, usageStart), originalAttrs, false, result); + addChunk(chars, Math.max(hiStart, usageStart), Math.min(hiEnd, usageEnd), originalAttrs, true, result); + addChunk(chars, Math.min(hiEnd, usageEnd), hiEnd, originalAttrs, false, result); + } + + private static void addChunk(CharSequence chars, int start, int end, TextAttributes originalAttrs, boolean bold, List result) { + if (start >= end) return; + String rText = chars.subSequence(start, end).toString(); + TextAttributes attrs = bold + ? TextAttributes.merge(originalAttrs, new TextAttributes(null, null, null, null, Font.BOLD)) + : originalAttrs; + result.add(new TextChunk(attrs, rText)); + } + + private static boolean rangeIntersect(int s1, int e1, int s2, int e2) { + return s2 < s1 && s1 < e2 || s2 < e1 && e1 < e2 + || s1 < s2 && s2 < e1 || s1 < e2 && e2 < e1 + || s1 == s2 && e1 == e2; + } + + private TextAttributes convertAttributes(TextAttributesKey[] keys) { + TextAttributes attrs = myColorsScheme.getAttributes(HighlighterColors.TEXT); + + for (int i = 0; i < keys.length; i++) { + TextAttributesKey key = keys[i]; + TextAttributes attrs2 = myColorsScheme.getAttributes(key); + if (attrs2 != null) { + attrs = TextAttributes.merge(attrs, attrs2); + } + } + + attrs = attrs.clone(); + attrs.setFontType(Font.PLAIN); + return attrs; + } + + private void appendPrefix(List result) { + StringBuffer buffer = new StringBuffer("("); + buffer.append(myLineNumber + 1); + buffer.append(", "); + buffer.append(myColumnNumber + 1); + buffer.append(") "); + TextChunk prefixChunk = new TextChunk(myColorsScheme.getAttributes(UsageTreeColors.USAGE_LOCATION), buffer.toString()); + result.add(prefixChunk); + } + + + +} diff --git a/UsageView/src/com/intellij/usages/UsageInfo2UsageAdapter.java b/UsageView/src/com/intellij/usages/UsageInfo2UsageAdapter.java index 96dd4cc9e0ce..ff252211a2a1 100644 --- a/UsageView/src/com/intellij/usages/UsageInfo2UsageAdapter.java +++ b/UsageView/src/com/intellij/usages/UsageInfo2UsageAdapter.java @@ -1,17 +1,12 @@ package com.intellij.usages; import com.intellij.ide.SelectInEditorManager; -import com.intellij.lexer.Lexer; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.HighlighterColors; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.editor.colors.EditorColorsScheme; -import com.intellij.openapi.editor.colors.TextAttributesKey; -import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.fileEditor.*; -import com.intellij.openapi.fileTypes.SyntaxHighlighter; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; @@ -21,15 +16,10 @@ import com.intellij.psi.PsiCompiledElement; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; -import com.intellij.psi.tree.IElementType; import com.intellij.usageView.UsageInfo; -import com.intellij.usageView.UsageTreeColors; -import com.intellij.usageView.UsageTreeColorsScheme; import com.intellij.usages.rules.*; -import com.intellij.util.text.CharArrayUtil; import javax.swing.*; -import java.awt.*; import java.util.ArrayList; import java.util.List; @@ -54,7 +44,6 @@ public class UsageInfo2UsageAdapter implements Usage, UsageInModule, UsageInLibr private EditorColorsScheme myColorsScheme; public UsageInfo2UsageAdapter(final UsageInfo usageInfo) { - myColorsScheme = UsageTreeColorsScheme.getInstance().getScheme(); myUsageInfo = usageInfo; PsiElement element = myUsageInfo.getElement(); myPsiFile = element.getContainingFile(); @@ -91,9 +80,7 @@ public class UsageInfo2UsageAdapter implements Usage, UsageInModule, UsageInLibr } private void initChunks() { - int lineStartOffset = myDocument.getLineStartOffset(myLineNumber); - int lineEndOffset = myDocument.getLineEndOffset(myLineNumber); - myTextChunks = createTextChunks(myDocument.getCharsSequence(), myPsiFile.getFileType().getHighlighter(myPsiFile.getProject()), lineStartOffset, lineEndOffset); + myTextChunks = new ChunkExtractor(myDocument, myLineNumber, myPsiFile, myRangeMarkers, myColumnNumber).extractChunks(); } public UsagePresentation getPresentation() { @@ -247,124 +234,6 @@ public class UsageInfo2UsageAdapter implements Usage, UsageInModule, UsageInLibr } } - private TextChunk[] createTextChunks(final CharSequence chars, - SyntaxHighlighter highlighter, - int start, - int end) { - LOG.assertTrue(start <= end); - List result = new ArrayList(); - - appendPrefix(result); - - Lexer lexer = highlighter.getHighlightingLexer(); - lexer.start(CharArrayUtil.fromSequence(chars)); - - for (int offset = start; offset < end; offset++) { - if (chars.charAt(offset) == '\n') { - end = offset; - break; - } - } - - boolean isBeginning = true; - - while (lexer.getTokenType() != null) { - try { - int hiStart = lexer.getTokenStart(); - int hiEnd = lexer.getTokenEnd(); - - if (hiStart >= end) break; - - hiStart = Math.max(hiStart, start); - hiEnd = Math.min(hiEnd, end); - if (hiStart >= hiEnd) { continue; } - - String text = chars.subSequence(hiStart, hiEnd).toString(); - if (isBeginning && text.trim().length() == 0) continue; - isBeginning = false; - IElementType tokenType = lexer.getTokenType(); - TextAttributesKey[] tokenHighlights = highlighter.getTokenHighlights(tokenType); - - RangeMarker intersectionMarker = getIntersectingMarker(hiStart, hiEnd); - if (intersectionMarker != null) { - processIntersectingRage(chars, hiStart, hiEnd, tokenHighlights, result, intersectionMarker); - } - else { - result.add(new TextChunk(convertAttributes(tokenHighlights), text)); - } - } - finally { - lexer.advance(); - } - } - - return result.toArray(new TextChunk[result.size()]); - } - - private RangeMarker getIntersectingMarker(int hiStart, int hiEnd) { - for (int i = 0; i < myRangeMarkers.size(); i++) { - RangeMarker marker = myRangeMarkers.get(i); - if (marker.isValid() && rangeIntersect(hiStart, hiEnd, marker.getStartOffset(), marker.getEndOffset())) return marker; - } - return null; - } - - private void processIntersectingRage(CharSequence chars, - int hiStart, - int hiEnd, - TextAttributesKey[] tokenHighlights, - List result, - RangeMarker rangeMarker) { - int usageStart = rangeMarker.getStartOffset(); - int usageEnd = rangeMarker.getEndOffset(); - - TextAttributes originalAttrs = convertAttributes(tokenHighlights); - addChunk(chars, hiStart, Math.max(hiStart, usageStart), originalAttrs, false, result); - addChunk(chars, Math.max(hiStart, usageStart), Math.min(hiEnd, usageEnd), originalAttrs, true, result); - addChunk(chars, Math.min(hiEnd, usageEnd), hiEnd, originalAttrs, false, result); - } - - private static void addChunk(CharSequence chars, int start, int end, TextAttributes originalAttrs, boolean bold, List result) { - if (start >= end) return; - String rText = chars.subSequence(start, end).toString(); - TextAttributes attrs = bold - ? TextAttributes.merge(originalAttrs, new TextAttributes(null, null, null, null, Font.BOLD)) - : originalAttrs; - result.add(new TextChunk(attrs, rText)); - } - - private static boolean rangeIntersect(int s1, int e1, int s2, int e2) { - return s2 < s1 && s1 < e2 || s2 < e1 && e1 < e2 - || s1 < s2 && s2 < e1 || s1 < e2 && e2 < e1 - || s1 == s2 && e1 == e2; - } - - private TextAttributes convertAttributes(TextAttributesKey[] keys) { - TextAttributes attrs = myColorsScheme.getAttributes(HighlighterColors.TEXT); - - for (int i = 0; i < keys.length; i++) { - TextAttributesKey key = keys[i]; - TextAttributes attrs2 = myColorsScheme.getAttributes(key); - if (attrs2 != null) { - attrs = TextAttributes.merge(attrs, attrs2); - } - } - - attrs = attrs.clone(); - attrs.setFontType(Font.PLAIN); - return attrs; - } - - private void appendPrefix(List result) { - StringBuffer buffer = new StringBuffer("("); - buffer.append(myLineNumber + 1); - buffer.append(", "); - buffer.append(myColumnNumber + 1); - buffer.append(") "); - TextChunk prefixChunk = new TextChunk(myColorsScheme.getAttributes(UsageTreeColors.USAGE_LOCATION), buffer.toString()); - result.add(prefixChunk); - } - public PsiElement getElement() { return myUsageInfo.getElement(); }