mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
introduce smart pointer getPsiRange, let getLastCommittedDocument work for injections
This commit is contained in:
@@ -73,6 +73,12 @@ public class IdentitySmartPointer<T extends PsiElement> implements SmartPsiEleme
|
||||
|
||||
@Override
|
||||
public Segment getRange() {
|
||||
return getPsiRange();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Segment getPsiRange() {
|
||||
return myElement.getTextRange();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,18 @@ public interface SmartPsiElementPointer<E extends PsiElement> {
|
||||
|
||||
VirtualFile getVirtualFile();
|
||||
|
||||
/**
|
||||
* @return the range in the document. For committed document, it's the same as {@link #getPsiRange()}, for non-committed documents
|
||||
* the ranges may be changed (like in {@link com.intellij.openapi.editor.RangeMarker}) or even invalidated. In the latter case returns null.
|
||||
* Returns null for invalid pointers.
|
||||
*/
|
||||
@Nullable
|
||||
Segment getRange();
|
||||
|
||||
/**
|
||||
* @return the range in the committed PSI file. May be different from {@link #getRange()} result when the document has been changed since commit.
|
||||
* Returns null for invalid pointers.
|
||||
*/
|
||||
@Nullable
|
||||
Segment getPsiRange();
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
public abstract class PsiDocumentManagerBase extends PsiDocumentManager implements DocumentListener, ProjectComponent {
|
||||
static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.PsiDocumentManagerImpl");
|
||||
@@ -582,14 +583,31 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FrozenDocument getLastCommittedDocument(@NotNull Document document) {
|
||||
if (document instanceof FrozenDocument) return (FrozenDocument)document;
|
||||
public DocumentEx getLastCommittedDocument(@NotNull Document document) {
|
||||
if (document instanceof FrozenDocument) return (DocumentEx)document;
|
||||
|
||||
if (document instanceof DocumentWindow) {
|
||||
DocumentWindow window = (DocumentWindow)document;
|
||||
Document delegate = window.getDelegate();
|
||||
if (delegate instanceof FrozenDocument) return (DocumentEx)window;
|
||||
|
||||
UncommittedInfo info = myUncommittedInfos.get(delegate);
|
||||
DocumentWindow answer = info == null ? null : info.myFrozenWindows.get(document);
|
||||
if (answer == null) answer = freezeWindow(window);
|
||||
if (info != null) answer = ConcurrencyUtil.cacheOrGet(info.myFrozenWindows, window, answer);
|
||||
return (DocumentEx)answer;
|
||||
}
|
||||
|
||||
assert document instanceof DocumentImpl;
|
||||
UncommittedInfo info = myUncommittedInfos.get(document);
|
||||
return info != null ? info.myFrozen : ((DocumentImpl)document).freeze();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected DocumentWindow freezeWindow(@NotNull DocumentWindow document) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<DocumentEvent> getEventsSinceCommit(@NotNull Document document) {
|
||||
assert document instanceof DocumentImpl;
|
||||
@@ -899,6 +917,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
|
||||
final DocumentImpl myOriginal;
|
||||
final FrozenDocument myFrozen;
|
||||
final List<DocumentEvent> myEvents = ContainerUtil.newArrayList();
|
||||
final ConcurrentMap<DocumentWindow, DocumentWindow> myFrozenWindows = ContainerUtil.newConcurrentMap();
|
||||
|
||||
public UncommittedInfo(DocumentImpl original) {
|
||||
myOriginal = original;
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.intellij.psi.PsiAnchor;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* User: cdr
|
||||
@@ -68,6 +69,12 @@ public class ClsElementInfo extends SmartPointerElementInfo {
|
||||
return myStubIndexReference.getProject();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Segment getPsiRange() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiFile restoreFile() {
|
||||
return myStubIndexReference.getFile();
|
||||
|
||||
@@ -16,14 +16,19 @@
|
||||
package com.intellij.psi.impl.smartPointers;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Segment;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.impl.PsiDocumentManagerBase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* User: cdr
|
||||
@@ -90,4 +95,12 @@ class FileElementInfo extends SmartPointerElementInfo {
|
||||
return myProject;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Segment getPsiRange() {
|
||||
Document currentDoc = FileDocumentManager.getInstance().getCachedDocument(myVirtualFile);
|
||||
Document committedDoc = currentDoc == null ? null :
|
||||
((PsiDocumentManagerBase)PsiDocumentManager.getInstance(myProject)).getLastCommittedDocument(currentDoc);
|
||||
return committedDoc == null ? getRange() : new TextRange(0, committedDoc.getTextLength());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,11 @@ class HardElementInfo extends SmartPointerElementInfo {
|
||||
return myElement.getTextRange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Segment getPsiRange() {
|
||||
return getRange();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Project getProject() {
|
||||
|
||||
+33
-25
@@ -28,6 +28,7 @@ import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.FreeThreadedFileViewProvider;
|
||||
import com.intellij.psi.impl.PsiDocumentManagerBase;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -72,7 +73,13 @@ class InjectedSelfElementInfo extends SmartPointerElementInfo {
|
||||
|
||||
@Override
|
||||
public Segment getRange() {
|
||||
return getInjectedRange();
|
||||
return getInjectedRange(false);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Segment getPsiRange() {
|
||||
return getInjectedRange(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -83,20 +90,14 @@ class InjectedSelfElementInfo extends SmartPointerElementInfo {
|
||||
PsiElement hostContext = myHostContext.getElement();
|
||||
if (hostContext == null) return null;
|
||||
|
||||
Segment segment = myInjectedFileRangeInHostFile.getRange();
|
||||
Segment segment = myInjectedFileRangeInHostFile.getPsiRange();
|
||||
if (segment == null) return null;
|
||||
final TextRange rangeInHostFile = TextRange.create(segment);
|
||||
|
||||
PsiElement result = null;
|
||||
PsiFile injectedPsi = getInjectedFileIn(hostContext, hostFile, rangeInHostFile);
|
||||
if (injectedPsi != null) {
|
||||
Document document = PsiDocumentManager.getInstance(getProject()).getDocument(injectedPsi);
|
||||
int start = ((DocumentWindow)document).hostToInjected(rangeInHostFile.getStartOffset());
|
||||
int end = ((DocumentWindow)document).hostToInjected(rangeInHostFile.getEndOffset());
|
||||
result = SelfElementInfo.findElementInside(injectedPsi, start, end, anchorClass, anchorLanguage);
|
||||
}
|
||||
PsiFile injectedPsi = getInjectedFileIn(hostContext, hostFile, TextRange.create(segment));
|
||||
ProperTextRange rangeInInjected = hostToInjected(true, segment, injectedPsi);
|
||||
if (rangeInInjected == null) return null;
|
||||
|
||||
return result;
|
||||
return SelfElementInfo.findElementInside(injectedPsi, rangeInInjected.getStartOffset(), rangeInInjected.getEndOffset(), anchorClass, anchorLanguage);
|
||||
}
|
||||
|
||||
private PsiFile getInjectedFileIn(@NotNull final PsiElement hostContext,
|
||||
@@ -161,24 +162,31 @@ class InjectedSelfElementInfo extends SmartPointerElementInfo {
|
||||
return getInjectedFileIn(hostContext, hostFile, rangeInHostFile);
|
||||
}
|
||||
|
||||
private ProperTextRange getInjectedRange() {
|
||||
PsiFile hostFile = myHostContext.getContainingFile();
|
||||
if (hostFile == null || !hostFile.isValid()) return null;
|
||||
|
||||
@Nullable
|
||||
private ProperTextRange getInjectedRange(boolean psi) {
|
||||
PsiElement hostContext = myHostContext.getElement();
|
||||
if (hostContext == null) return null;
|
||||
|
||||
Segment hostElementRange = myInjectedFileRangeInHostFile.getRange();
|
||||
Segment hostElementRange = psi ? myInjectedFileRangeInHostFile.getPsiRange() : myInjectedFileRangeInHostFile.getRange();
|
||||
if (hostElementRange == null) return null;
|
||||
|
||||
PsiFile injectedFile = restoreFile();
|
||||
if (injectedFile == null) return null;
|
||||
VirtualFile virtualFile = injectedFile.getVirtualFile();
|
||||
DocumentWindow documentWindow = virtualFile instanceof VirtualFileWindow ? ((VirtualFileWindow)virtualFile).getDocumentWindow() : null;
|
||||
if (documentWindow==null) return null;
|
||||
int start = documentWindow.hostToInjected(hostElementRange.getStartOffset());
|
||||
int end = documentWindow.hostToInjected(hostElementRange.getEndOffset());
|
||||
return ProperTextRange.create(start, end);
|
||||
return hostToInjected(psi, hostElementRange, restoreFile());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ProperTextRange hostToInjected(boolean psi, Segment hostRange, @Nullable PsiFile injectedFile) {
|
||||
VirtualFile virtualFile = injectedFile == null ? null : injectedFile.getVirtualFile();
|
||||
if (virtualFile instanceof VirtualFileWindow) {
|
||||
DocumentWindow documentWindow = ((VirtualFileWindow)virtualFile).getDocumentWindow();
|
||||
if (psi) {
|
||||
documentWindow = (DocumentWindow) ((PsiDocumentManagerBase) PsiDocumentManager.getInstance(getProject())).getLastCommittedDocument(documentWindow);
|
||||
}
|
||||
int start = documentWindow.hostToInjected(hostRange.getStartOffset());
|
||||
int end = documentWindow.hostToInjected(hostRange.getEndOffset());
|
||||
return ProperTextRange.create(start, end);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.editor.impl.FrozenDocument;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.*;
|
||||
@@ -109,7 +110,8 @@ public class SelfElementInfo extends SmartPointerElementInfo {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected ProperTextRange getPsiRange() {
|
||||
@Override
|
||||
public ProperTextRange getPsiRange() {
|
||||
return calcPsiRange();
|
||||
}
|
||||
|
||||
@@ -248,7 +250,7 @@ public class SelfElementInfo extends SmartPointerElementInfo {
|
||||
PsiDocumentManagerBase documentManager = myManager.getPsiDocumentManager();
|
||||
List<DocumentEvent> events = documentManager.getEventsSinceCommit(document);
|
||||
if (!events.isEmpty()) {
|
||||
return myMarkerCache.getUpdatedRange(markerCacheKey(), documentManager.getLastCommittedDocument(document), events);
|
||||
return myMarkerCache.getUpdatedRange(markerCacheKey(), (FrozenDocument)documentManager.getLastCommittedDocument(document), events);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -51,4 +51,7 @@ abstract class SmartPointerElementInfo {
|
||||
|
||||
public void cleanup() {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public abstract Segment getPsiRange();
|
||||
}
|
||||
|
||||
+6
@@ -128,6 +128,12 @@ class SmartPsiElementPointerImpl<E extends PsiElement> implements SmartPointerEx
|
||||
return myElementInfo.getRange();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Segment getPsiRange() {
|
||||
return myElementInfo.getPsiRange();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static <E extends PsiElement> SmartPointerElementInfo createElementInfo(@NotNull Project project,
|
||||
@NotNull E element,
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.intellij.psi.impl;
|
||||
|
||||
import com.intellij.AppTopics;
|
||||
import com.intellij.injected.editor.DocumentWindow;
|
||||
import com.intellij.injected.editor.DocumentWindowImpl;
|
||||
import com.intellij.injected.editor.EditorWindowImpl;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.SettingsSavingComponent;
|
||||
@@ -39,6 +40,7 @@ import com.intellij.psi.FileViewProvider;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.impl.source.PostprocessReformattingAspect;
|
||||
import com.intellij.psi.impl.source.tree.injected.MultiHostRegistrarImpl;
|
||||
import com.intellij.util.FileContentUtil;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.messages.MessageBus;
|
||||
@@ -188,4 +190,10 @@ public class PsiDocumentManagerImpl extends PsiDocumentManagerBase implements Se
|
||||
public void reparseFiles(@NotNull Collection<VirtualFile> files, boolean includeOpenFiles) {
|
||||
FileContentUtil.reparseFiles(myProject, files, includeOpenFiles);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected DocumentWindow freezeWindow(@NotNull DocumentWindow document) {
|
||||
return MultiHostRegistrarImpl.freezeWindow((DocumentWindowImpl)document);
|
||||
}
|
||||
}
|
||||
|
||||
+17
-1
@@ -55,7 +55,9 @@ import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.testFramework.LightVirtualFile;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -189,7 +191,7 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
|
||||
SmartPointerManagerImpl manager = (SmartPointerManagerImpl)SmartPointerManager.getInstance(myProject);
|
||||
shreds.add(new ShredImpl(manager.createSmartPsiFileRangePointer(myHostPsiFile, relevantRangeInHost, true),
|
||||
manager.createSmartPsiElementPointer(host, myHostPsiFile),
|
||||
prefix, suffix, new ProperTextRange(startOffset, endOffset)));
|
||||
prefix, suffix, new ProperTextRange(startOffset, endOffset), false));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -551,4 +553,18 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
|
||||
ReferenceInjector getReferenceInjector() {
|
||||
return myReferenceInjector;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static DocumentWindow freezeWindow(@NotNull DocumentWindowImpl window) {
|
||||
Place shreds = window.getShreds();
|
||||
Project project = shreds.getHostPointer().getProject();
|
||||
DocumentEx delegate = ((PsiDocumentManagerBase)PsiDocumentManager.getInstance(project)).getLastCommittedDocument(window.getDelegate());
|
||||
Place place = new Place(ContainerUtil.map(shreds, new Function<PsiLanguageInjectionHost.Shred, PsiLanguageInjectionHost.Shred>() {
|
||||
@Override
|
||||
public PsiLanguageInjectionHost.Shred fun(final PsiLanguageInjectionHost.Shred shred) {
|
||||
return ((ShredImpl) shred).withPsiRange();
|
||||
}
|
||||
}));
|
||||
return new DocumentWindowImpl(delegate, window.isOneLine(), place);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,20 +28,27 @@ class ShredImpl implements PsiLanguageInjectionHost.Shred {
|
||||
private final TextRange range; // range in (decoded) PSI
|
||||
private final String prefix;
|
||||
private final String suffix;
|
||||
private final boolean usePsiRange;
|
||||
|
||||
ShredImpl(@NotNull SmartPsiFileRange relevantRangeInHost,
|
||||
@NotNull SmartPsiElementPointer<PsiLanguageInjectionHost> hostElementPointer,
|
||||
@NotNull String prefix,
|
||||
@NotNull String suffix,
|
||||
@NotNull TextRange range) {
|
||||
@NotNull TextRange range,
|
||||
boolean usePsiRange) {
|
||||
this.hostElementPointer = hostElementPointer;
|
||||
this.relevantRangeInHost = relevantRangeInHost;
|
||||
this.prefix = prefix;
|
||||
this.suffix = suffix;
|
||||
this.range = range;
|
||||
this.usePsiRange = usePsiRange;
|
||||
assert isValid();
|
||||
}
|
||||
|
||||
ShredImpl withPsiRange() {
|
||||
return new ShredImpl(relevantRangeInHost, hostElementPointer, prefix, suffix, range, true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public SmartPsiElementPointer<PsiLanguageInjectionHost> getSmartPointer() {
|
||||
return hostElementPointer;
|
||||
@@ -50,18 +57,18 @@ class ShredImpl implements PsiLanguageInjectionHost.Shred {
|
||||
@Override
|
||||
@Nullable("returns null when the host document marker is invalid")
|
||||
public Segment getHostRangeMarker() {
|
||||
return relevantRangeInHost.getRange();
|
||||
return usePsiRange ? relevantRangeInHost.getPsiRange() : relevantRangeInHost.getRange();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public TextRange getRangeInsideHost() {
|
||||
PsiLanguageInjectionHost host = getHost();
|
||||
Segment psiRange = relevantRangeInHost.getRange();
|
||||
Segment psiRange = relevantRangeInHost.getPsiRange();
|
||||
TextRange textRange = psiRange == null ? null : TextRange.create(psiRange);
|
||||
if (host == null) {
|
||||
if (textRange != null) return textRange;
|
||||
Segment fromSP = hostElementPointer.getRange();
|
||||
Segment fromSP = hostElementPointer.getPsiRange();
|
||||
if (fromSP != null) return TextRange.create(fromSP);
|
||||
return new TextRange(0,0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user