IDEA-67711

This commit is contained in:
Alexey Kudravtsev
2011-04-08 14:13:06 +04:00
parent 631f0438af
commit 4a515dcda0
10 changed files with 97 additions and 29 deletions
@@ -52,12 +52,12 @@ class AnchorElementInfo extends SelfElementInfo {
@Nullable
public PsiElement restoreElement() {
if (stubId != -1) {
PsiFile file = SelfElementInfo.restoreFileFromVirtual(myVirtualFile, myProject);
PsiFile file = SelfElementInfo.restoreFileFromVirtual(getVirtualFile(), myProject);
if (!(file instanceof PsiFileWithStubSupport)) return null;
return PsiAnchor.restoreFromStubIndex((PsiFileWithStubSupport)file, stubId, myStubElementType);
}
if (!mySyncMarkerIsValid) return null;
PsiFile file = SelfElementInfo.restoreFileFromVirtual(myVirtualFile, myProject);
PsiFile file = SelfElementInfo.restoreFileFromVirtual(getVirtualFile(), myProject);
if (file == null) return null;
PsiElement anchor = file.findElementAt(getSyncStartOffset());
if (anchor == null) return null;
@@ -16,6 +16,7 @@
package com.intellij.psi;
import com.intellij.openapi.util.Segment;
import org.jetbrains.annotations.Nullable;
/**
* pointer to a PsiFile + range inside the file.
@@ -25,5 +26,6 @@ public interface SmartPsiFileRange extends SmartPsiElementPointer<PsiFile> {
/**
* @return the range inside the PsiFile, or null if the range or PsiFile became invalid
*/
@Nullable
Segment getRange();
}
@@ -362,7 +362,7 @@ public class ReplaceInProjectManager {
for (final Usage usage : selectedUsages) {
final VirtualFile file = ((UsageInFile)usage).getFile();
if (!file.isWritable()) {
if (file != null && !file.isWritable()) {
if (readOnlyFiles == null) readOnlyFiles = new HashSet<VirtualFile>();
readOnlyFiles.add(file);
}
@@ -17,24 +17,64 @@ package com.intellij.psi.impl.smartPointers;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.Segment;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* User: cdr
*/
class InjectedSelfElementInfo extends SelfElementInfo {
private final SmartPsiFileRange myPsiFileRangeInHostElement;
private final Class<? extends PsiElement> myClass;
InjectedSelfElementInfo(@NotNull Project project,
@NotNull PsiElement anchor,
@NotNull PsiFile containingFile) {
super(project, InjectedLanguageManager.getInstance(project).injectedToHost(anchor, anchor.getTextRange()), anchor.getClass(), InjectedLanguageUtil.getTopLevelFile(containingFile));
assert containingFile.getContext() != null;
@NotNull PsiElement context) {
super(project, context);
SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(project);
myPsiFileRangeInHostElement = smartPointerManager.createSmartPsiFileRangePointer(context.getContainingFile(), InjectedLanguageManager.getInstance(
project).injectedToHost(anchor, anchor.getTextRange()));
myClass = anchor.getClass();
}
@Override
protected PsiElement findAnchorAt(@NotNull PsiFile file, int syncStartOffset) {
return InjectedLanguageUtil.findInjectedElementNoCommitWithOffset(file, syncStartOffset);
public VirtualFile getVirtualFile() {
PsiElement element = restoreElement();
if (element == null) return null;
return element.getContainingFile().getVirtualFile();
}
@Override
public PsiElement restoreElement() {
PsiElement host = super.restoreElement();
if (host == null) return null;
Segment segment = myPsiFileRangeInHostElement.getRange();
if (segment == null) return null;
final TextRange rangeInHostElement = TextRange.create(segment);
final Ref<PsiElement> result = new Ref<PsiElement>();
InjectedLanguageUtil.enumerate(host, host.getContainingFile(), new PsiLanguageInjectionHost.InjectedPsiVisitor() {
@Override
public void visit(@NotNull PsiFile injectedPsi, @NotNull List<PsiLanguageInjectionHost.Shred> places) {
if (result.get() != null) return;
TextRange hostRange =
InjectedLanguageManager.getInstance(getProject()).injectedToHost(injectedPsi, new TextRange(0, injectedPsi.getTextLength()));
if (hostRange.contains(rangeInHostElement)) {
TextRange rangeInside = rangeInHostElement.shiftRight(-hostRange.getStartOffset());
PsiElement element = findElementInside(injectedPsi, rangeInside.getStartOffset(), rangeInside.getEndOffset(), myClass);
result.set(element);
}
}
}, false);
return result.get();
}
}
@@ -34,7 +34,7 @@ import java.lang.ref.SoftReference;
* User: cdr
*/
public class SelfElementInfo implements SmartPointerElementInfo {
protected final VirtualFile myVirtualFile;
private final VirtualFile myVirtualFile;
private Reference<RangeMarker> myMarkerRef; // create marker only in case of live document
private int mySyncStartOffset;
private int mySyncEndOffset;
@@ -44,6 +44,9 @@ public class SelfElementInfo implements SmartPointerElementInfo {
@SuppressWarnings({"UnusedDeclaration"})
private RangeMarker myRangeMarker; //maintain hard reference during modification
protected SelfElementInfo(@NotNull Project project, @NotNull PsiElement anchor) {
this(project, anchor.getTextRange(), anchor.getClass(), anchor.getContainingFile());
}
public SelfElementInfo(@NotNull Project project, @NotNull TextRange anchor, @NotNull Class anchorClass, @NotNull PsiFile containingFile) {
myVirtualFile = containingFile.getVirtualFile();
myType = anchorClass;
@@ -154,7 +157,11 @@ public class SelfElementInfo implements SmartPointerElementInfo {
final int syncStartOffset = getSyncStartOffset();
final int syncEndOffset = getSyncEndOffset();
PsiElement anchor = findAnchorAt(file, syncStartOffset);
return findElementInside(file, syncStartOffset, syncEndOffset, myType);
}
protected static PsiElement findElementInside(PsiFile file, int syncStartOffset, int syncEndOffset, Class type) {
PsiElement anchor = file.getViewProvider().findElementAt(syncStartOffset, file.getLanguage());
if (anchor == null) return null;
TextRange range = anchor.getTextRange();
@@ -166,7 +173,7 @@ public class SelfElementInfo implements SmartPointerElementInfo {
range = anchor.getTextRange();
}
while (range.getEndOffset() == syncEndOffset && anchor != null && !myType.equals(anchor.getClass())) {
while (range.getEndOffset() == syncEndOffset && anchor != null && !type.equals(anchor.getClass())) {
anchor = anchor.getParent();
if (anchor == null || anchor.getTextRange() == null) break;
range = anchor.getTextRange();
@@ -176,10 +183,6 @@ public class SelfElementInfo implements SmartPointerElementInfo {
return null;
}
protected PsiElement findAnchorAt(@NotNull PsiFile file, int syncStartOffset) {
return file.getViewProvider().findElementAt(syncStartOffset, file.getLanguage());
}
@Override
public void dispose() {
RangeMarker marker = getMarker();
@@ -153,7 +153,8 @@ class SmartPsiElementPointerImpl<E extends PsiElement> implements SmartPointerEx
FileViewProvider viewProvider = containingFile.getViewProvider();
if (viewProvider instanceof InjectedFileViewProvider) {
return new InjectedSelfElementInfo(project, element, containingFile);
PsiElement context = containingFile.getContext();
if (context != null) return new InjectedSelfElementInfo(project, element, context);
}
if (element instanceof PsiFile) {
@@ -15,6 +15,7 @@
*/
package com.intellij.usages;
import com.intellij.injected.editor.DocumentWindow;
import com.intellij.lexer.Lexer;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
@@ -26,6 +27,7 @@ import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.PlainSyntaxHighlighter;
import com.intellij.openapi.fileTypes.SyntaxHighlighter;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Segment;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiDocumentManager;
@@ -101,10 +103,11 @@ public class ChunkExtractor {
private ChunkExtractor(@NotNull PsiFile file) {
myColorsScheme = UsageTreeColorsScheme.getInstance().getScheme();
myDocument = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
Project project = file.getProject();
myDocument = PsiDocumentManager.getInstance(project).getDocument(file);
LOG.assertTrue(myDocument != null);
final FileType fileType = file.getFileType();
final SyntaxHighlighter highlighter = SyntaxHighlighter.PROVIDER.create(fileType, file.getProject(), file.getVirtualFile());
final SyntaxHighlighter highlighter = SyntaxHighlighter.PROVIDER.create(fileType, project, file.getVirtualFile());
myHighlighter = highlighter == null ? new PlainSyntaxHighlighter() : highlighter;
myLexer = myHighlighter.getHighlightingLexer();
myLexer.start(myDocument.getCharsSequence());
@@ -125,8 +128,15 @@ public class ChunkExtractor {
int absoluteStartOffset = usageInfo2UsageAdapter.getNavigationOffset();
if (absoluteStartOffset == -1) return TextChunk.EMPTY_ARRAY;
final int lineNumber = myDocument.getLineNumber(absoluteStartOffset);
final int columnNumber = absoluteStartOffset - myDocument.getLineStartOffset(lineNumber);
Document visibleDocument = myDocument instanceof DocumentWindow ? ((DocumentWindow)myDocument).getDelegate() : myDocument;
int visibleStartOffset = myDocument instanceof DocumentWindow ? ((DocumentWindow)myDocument).injectedToHost(absoluteStartOffset) : absoluteStartOffset;
int lineNumber = myDocument.getLineNumber(absoluteStartOffset);
//int columnNumber = absoluteStartOffset - myDocument.getLineStartOffset(lineNumber);
int visibleLineNumber = visibleDocument.getLineNumber(visibleStartOffset);
int visibleColumnNumber = visibleStartOffset - visibleDocument.getLineStartOffset(visibleLineNumber);
final List<TextChunk> result = new ArrayList<TextChunk>();
appendPrefix(result, visibleLineNumber, visibleColumnNumber);
int lineStartOffset = myDocument.getLineStartOffset(lineNumber);
int lineEndOffset = lineStartOffset < myDocument.getTextLength() ? myDocument.getLineEndOffset(lineNumber) : 0;
@@ -136,8 +146,6 @@ public class ChunkExtractor {
if (myLexer.getTokenStart() > absoluteStartOffset) {
myLexer.start(chars);
}
final List<TextChunk> result = new ArrayList<TextChunk>();
appendPrefix(result, lineNumber, columnNumber);
if (lineEndOffset - lineStartOffset > MAX_LINE_TO_SHOW) {
lineStartOffset = Math.max(lineStartOffset, absoluteStartOffset - OFFSET_BEFORE_TO_SHOW_WHEN_LONG_LINE);
lineEndOffset = Math.min(lineEndOffset, absoluteStartOffset + OFFSET_AFTER_TO_SHOW_WHEN_LONG_LINE);
@@ -41,7 +41,7 @@ public class UsageDataUtil {
for (Usage usage : usages) {
if (usage instanceof UsageInFile) {
VirtualFile file = ((UsageInFile)usage).getFile();
if (file.isValid()) {
if (file != null && file.isValid()) {
result.add(file);
}
}
@@ -16,6 +16,7 @@
package com.intellij.usages;
import com.intellij.ide.SelectInEditorManager;
import com.intellij.injected.editor.VirtualFileWindow;
import com.intellij.openapi.actionSystem.DataKey;
import com.intellij.openapi.actionSystem.DataSink;
import com.intellij.openapi.actionSystem.TypeSafeDataProvider;
@@ -79,7 +80,7 @@ public class UsageInfo2UsageAdapter implements UsageInModule,
@Override
public void run() {
PsiElement element = getElement();
Document document = getDocument();
Document document = PsiDocumentManager.getInstance(getProject()).getDocument(element.getContainingFile());
int startOffset = myUsageInfo.getNavigationOffset();
if (document != null) {
@@ -197,7 +198,8 @@ public class UsageInfo2UsageAdapter implements UsageInModule,
}
public boolean canNavigate() {
return getFile().isValid();
VirtualFile file = getFile();
return file != null && file.isValid();
}
public boolean canNavigateToSource() {
@@ -323,16 +325,27 @@ public class UsageInfo2UsageAdapter implements UsageInModule,
return myUsageInfo;
}
// by start offset
public int compareTo(final UsageInfo2UsageAdapter o) {
VirtualFile containingFile = getFile();
int shift1 = 0;
if (containingFile instanceof VirtualFileWindow) {
shift1 = ((VirtualFileWindow)containingFile).getDocumentWindow().injectedToHost(0);
containingFile = ((VirtualFileWindow)containingFile).getDelegate();
}
VirtualFile oContainingFile = o.getFile();
int shift2 = 0;
if (oContainingFile instanceof VirtualFileWindow) {
shift2 = ((VirtualFileWindow)oContainingFile).getDocumentWindow().injectedToHost(0);
oContainingFile = ((VirtualFileWindow)oContainingFile).getDelegate();
}
if (containingFile == null && oContainingFile == null || !Comparing.equal(containingFile, oContainingFile)) {
return 0;
}
Segment s1 = getFirstSegment();
Segment s2 = o.getFirstSegment();
if (s1 == null || s2 == null) return 0;
return s1.getStartOffset() - s2.getStartOffset();
return s1.getStartOffset() + shift1 - s2.getStartOffset() - shift2;
}
public void rename(String newName) throws IncorrectOperationException {
@@ -909,7 +909,8 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra
for (Usage usage : usages) {
if (usage instanceof UsageInFile) {
UsageInFile usageInFile = (UsageInFile)usage;
result.add(usageInFile.getFile());
VirtualFile file = usageInFile.getFile();
if (file != null) result.add(file);
}
if (usage instanceof UsageInFiles) {