chunk extractor

This commit is contained in:
Peter Gromov
2005-02-08 22:51:44 +03:00
parent 539bf7ab33
commit 5d70dd6097
2 changed files with 179 additions and 132 deletions
@@ -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<RangeMarker> myRangeMarkers;
private EditorColorsScheme myColorsScheme;
private int myColumnNumber;
public ChunkExtractor(final Document document,
final int lineNumber,
final PsiFile psiFile,
final List<RangeMarker> 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<TextChunk> result = new ArrayList<TextChunk>();
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<TextChunk> 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<TextChunk> 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<TextChunk> 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);
}
}
@@ -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<TextChunk> result = new ArrayList<TextChunk>();
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<TextChunk> 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<TextChunk> 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<TextChunk> 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();
}