separate single and multi root injected file view providers

GitOrigin-RevId: 2019303584a968437956c9e153df851606f71313
This commit is contained in:
Dennis Ushakov
2019-10-03 13:06:01 +00:00
committed by intellij-monorepo-bot
parent 4d34b046a6
commit d21c55c102
4 changed files with 288 additions and 148 deletions
@@ -1,19 +1,4 @@
/*
* Copyright 2000-2015 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.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.psi.impl.source.tree.injected;
import com.intellij.injected.editor.DocumentWindow;
@@ -21,56 +6,32 @@ import com.intellij.injected.editor.VirtualFileWindow;
import com.intellij.lang.Language;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.Segment;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.FreeThreadedFileViewProvider;
import com.intellij.psi.impl.PsiManagerEx;
import com.intellij.psi.impl.source.PsiFileImpl;
import com.intellij.psi.templateLanguages.TemplateLanguageFileViewProvider;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.containers.ContainerUtil;
import org.apache.commons.lang.NotImplementedException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Set;
/**
* @deprecated Use methods from {@link InjectedLanguageManager} instead
*/
@Deprecated
public class InjectedFileViewProvider extends MultiplePsiFilesPerDocumentFileViewProvider implements FreeThreadedFileViewProvider {
private final Object myLock = new Object();
private final DocumentWindowImpl myDocumentWindow;
private final Language myLanguage;
private static final ThreadLocal<Boolean> disabledTemporarily = ThreadLocal.withInitial(() -> false);
private boolean myPatchingLeaves;
protected final AbstractFileViewProvider myOriginalProvider;
public interface InjectedFileViewProvider extends FileViewProvider, FreeThreadedFileViewProvider {
Key<Language> LANGUAGE_FOR_INJECTED_COPY_KEY = Key.create("LANGUAGE_FOR_INJECTED_COPY_KEY");
ThreadLocal<Boolean> disabledTemporarily = ThreadLocal.withInitial(() -> false);
private InjectedFileViewProvider(@NotNull PsiManager psiManager,
@NotNull VirtualFileWindow virtualFile,
@NotNull DocumentWindowImpl documentWindow,
@NotNull Language language, AbstractFileViewProvider original) {
super(psiManager, (VirtualFile)virtualFile, true);
myDocumentWindow = documentWindow;
myLanguage = language;
myOriginalProvider = original;
}
@Override
public void rootChanged(@NotNull PsiFile psiFile) {
super.rootChanged(psiFile);
default void rootChangedImpl(@NotNull PsiFile psiFile) {
if (!isPhysical()) return; // injected PSI change happened inside reparse; ignore
if (myPatchingLeaves) return;
if (getPatchingLeaves()) return;
DocumentWindowImpl documentWindow = myDocumentWindow;
DocumentWindowImpl documentWindow = getDocument();
List<PsiLanguageInjectionHost.Shred> shreds = documentWindow.getShreds();
assert documentWindow.getHostRanges().length == shreds.size();
String[] changes = documentWindow.calculateMinEditSequence(psiFile.getNode().getText());
@@ -88,8 +49,7 @@ public class InjectedFileViewProvider extends MultiplePsiFilesPerDocumentFileVie
}
}
@Override
public FileViewProvider clone() {
default FileViewProvider cloneImpl() {
final DocumentWindow oldDocumentWindow = ((VirtualFileWindow)getVirtualFile()).getDocumentWindow();
Document hostDocument = oldDocumentWindow.getDelegate();
final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(getManager().getProject());
@@ -121,47 +81,20 @@ public class InjectedFileViewProvider extends MultiplePsiFilesPerDocumentFileVie
return provider.get();
}
static Key<Language> LANGUAGE_FOR_INJECTED_COPY_KEY = Key.create("LANGUAGE_FOR_INJECTED_COPY_KEY");
// returns true if shreds were set, false if old ones were reused
boolean setShreds(@NotNull Place newShreds) {
synchronized (myLock) {
Place oldShreds = myDocumentWindow.getShreds();
default boolean setShreds(@NotNull Place newShreds) {
synchronized (getLock()) {
Place oldShreds = getDocument().getShreds();
// try to reuse shreds, otherwise there are too many range markers disposals/re-creations
if (same(oldShreds, newShreds)) {
return false;
}
myDocumentWindow.setShreds(newShreds);
getDocument().setShreds(newShreds);
return true;
}
}
@NotNull
private Project getProject() {
return getManager().getProject();
}
@NotNull
@Override
public Language getBaseLanguage() {
return myLanguage;
}
@NotNull
@Override
public Set<Language> getLanguages() {
FileViewProvider original = myOriginalProvider;
Set<Language> languages = original.getLanguages();
Language base = original.getBaseLanguage();
return ContainerUtil.map2Set(languages, (language) -> language == base ? myLanguage : language);
}
@NotNull
@Override
protected MultiplePsiFilesPerDocumentFileViewProvider cloneInner(@NotNull VirtualFile fileCopy) {
throw new NotImplementedException();
}
private static boolean same(Place oldShreds, Place newShreds) {
static boolean same(Place oldShreds, Place newShreds) {
if (oldShreds == newShreds) return true;
if (oldShreds.size() != newShreds.size()) return false;
for (int i = 0; i < oldShreds.size(); i++) {
@@ -172,36 +105,12 @@ public class InjectedFileViewProvider extends MultiplePsiFilesPerDocumentFileVie
return true;
}
boolean isValid() {
return getShreds().isValid();
}
boolean isDisposed() {
return getProject().isDisposed();
}
Place getShreds() {
return myDocumentWindow.getShreds();
}
@Override
@NotNull
public DocumentWindow getDocument() {
return myDocumentWindow;
}
@Override
public boolean isEventSystemEnabled() {
return !disabledTemporarily.get();
}
@Override
public boolean isPhysical() {
default boolean isPhysicalImpl() {
return isEventSystemEnabled();
}
void performNonPhysically(Runnable runnable) {
synchronized (myLock) {
default void performNonPhysically(Runnable runnable) {
synchronized (getLock()) {
disabledTemporarily.set(true);
try {
runnable.run();
@@ -212,56 +121,50 @@ public class InjectedFileViewProvider extends MultiplePsiFilesPerDocumentFileVie
}
}
@NonNls
@Override
public String toString() {
return "Injected file '"+getVirtualFile().getName()+"' " + (isValid() ? "" : " invalid") + (isPhysical() ? "" : " nonphysical");
}
void doNotInterruptMeWhileImPatchingLeaves(@NotNull Runnable runnable) {
myPatchingLeaves = true;
default void doNotInterruptMeWhileImPatchingLeaves(@NotNull Runnable runnable) {
setPatchingLeaves(true);
try {
runnable.run();
}
finally {
myPatchingLeaves = false;
setPatchingLeaves(false);
}
}
public final void forceCachedPsi(@NotNull PsiFile psiFile) {
myRoots.put(psiFile.getLanguage(), (PsiFileImpl)psiFile);
getManager().getFileManager().setViewProvider(getVirtualFile(), this);
void setPatchingLeaves(boolean value);
boolean getPatchingLeaves();
void forceCachedPsi(@NotNull PsiFile file);
Object getLock();
default boolean isValid() {
return getShreds().isValid();
}
static InjectedFileViewProvider create(PsiManagerEx manager,
VirtualFileWindowImpl file,
DocumentWindowImpl window,
Language language) {
default boolean isDisposed() {
return getManager().getProject().isDisposed();
}
default Place getShreds() {
return getDocument().getShreds();
}
default boolean isEventSystemEnabledImpl() {
return !disabledTemporarily.get();
}
@Override
@NotNull
DocumentWindowImpl getDocument();
static InjectedFileViewProvider create(@NotNull PsiManagerEx manager,
@NotNull VirtualFileWindowImpl file,
@NotNull DocumentWindowImpl window,
@NotNull Language language) {
AbstractFileViewProvider original = (AbstractFileViewProvider)manager.getFileManager().createFileViewProvider(file, false);
return original instanceof TemplateLanguageFileViewProvider ?
new Template(manager, file, window, language, original) :
new InjectedFileViewProvider(manager, file, window, language, original);
}
private static final class Template extends InjectedFileViewProvider implements TemplateLanguageFileViewProvider {
private Template(@NotNull PsiManagerEx psiManager,
@NotNull VirtualFileWindow virtualFile,
@NotNull DocumentWindowImpl documentWindow,
@NotNull Language language,
AbstractFileViewProvider original) {
super(psiManager, virtualFile, documentWindow, language, original);
assert myOriginalProvider instanceof TemplateLanguageFileViewProvider;
}
@NotNull
@Override
public Language getTemplateDataLanguage() {
return ((TemplateLanguageFileViewProvider)myOriginalProvider).getTemplateDataLanguage();
}
@Override
public IElementType getContentElementType(Language language, PsiFile file) {
return ((TemplateLanguageFileViewProvider)myOriginalProvider).getContentElementType(language, file);
}
new MultipleRootsInjectedFileViewProvider.Template(manager, file, window, language, original) :
original instanceof MultiplePsiFilesPerDocumentFileViewProvider ?
new MultipleRootsInjectedFileViewProvider(manager, file, window, language, original) :
new SingleRootInjectedFileViewProvider(manager, file, window, language);
}
}
@@ -606,7 +606,7 @@ class InjectionRegistrarImpl extends MultiHostRegistrarImpl implements MultiHost
ASTNode[] parsedNodes = parseFile(language, language, oldDocumentWindow,
hostVirtualFile, hostDocument, hostPsiFile, project, newDocumentText, placeInfos, chars,
fileName, documentManager);
List<PsiFile> oldFiles = oldInjectedPsiViewProvider.getCachedPsiFiles();
List<PsiFile> oldFiles = ((AbstractFileViewProvider)oldInjectedPsiViewProvider).getCachedPsiFiles();
synchronized (InjectedLanguageManagerImpl.ourInjectionPsiLock) {
DiffLog[] diffLogs = new DiffLog[parsedNodes.length];
for (int i = 0; i < parsedNodes.length; i++) {
@@ -0,0 +1,148 @@
/*
* Copyright 2000-2015 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.psi.impl.source.tree.injected;
import com.intellij.injected.editor.VirtualFileWindow;
import com.intellij.lang.Language;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.FreeThreadedFileViewProvider;
import com.intellij.psi.impl.PsiManagerEx;
import com.intellij.psi.impl.source.PsiFileImpl;
import com.intellij.psi.templateLanguages.TemplateLanguageFileViewProvider;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
public class MultipleRootsInjectedFileViewProvider extends MultiplePsiFilesPerDocumentFileViewProvider implements FreeThreadedFileViewProvider, InjectedFileViewProvider {
private final Object myLock = new Object();
private final DocumentWindowImpl myDocumentWindow;
private final Language myLanguage;
private boolean myPatchingLeaves;
protected final AbstractFileViewProvider myOriginalProvider;
MultipleRootsInjectedFileViewProvider(@NotNull PsiManager psiManager,
@NotNull VirtualFileWindow virtualFile,
@NotNull DocumentWindowImpl documentWindow,
@NotNull Language language,
@NotNull AbstractFileViewProvider original) {
super(psiManager, (VirtualFile)virtualFile, true);
myDocumentWindow = documentWindow;
myLanguage = language;
myOriginalProvider = original;
}
@Override
public Object getLock() {
return myLock;
}
@Override
public void setPatchingLeaves(boolean value) {
myPatchingLeaves = value;
}
@Override
public boolean getPatchingLeaves() {
return myPatchingLeaves;
}
@Override
public FileViewProvider clone() {
return cloneImpl();
}
@Override
public void rootChanged(@NotNull PsiFile psiFile) {
super.rootChanged(psiFile);
rootChangedImpl(psiFile);
}
@Override
public boolean isEventSystemEnabled() {
return isEventSystemEnabledImpl();
}
@Override
public boolean isPhysical() {
return isPhysicalImpl();
}
@NotNull
@Override
public Language getBaseLanguage() {
return myLanguage;
}
@NotNull
@Override
public Set<Language> getLanguages() {
FileViewProvider original = myOriginalProvider;
Set<Language> languages = original.getLanguages();
Language base = original.getBaseLanguage();
return ContainerUtil.map2Set(languages, (language) -> language == base ? myLanguage : language);
}
@NotNull
@Override
protected MultiplePsiFilesPerDocumentFileViewProvider cloneInner(@NotNull VirtualFile fileCopy) {
return (MultiplePsiFilesPerDocumentFileViewProvider)getManager().getFileManager().createFileViewProvider(fileCopy, false);
}
@Override
@NotNull
public DocumentWindowImpl getDocument() {
return myDocumentWindow;
}
@NonNls
@Override
public String toString() {
return "Multi root injected file '"+getVirtualFile().getName()+"' " + (isValid() ? "" : " invalid") + (isPhysical() ? "" : " nonphysical");
}
@Override
public final void forceCachedPsi(@NotNull PsiFile psiFile) {
myRoots.put(psiFile.getLanguage(), (PsiFileImpl)psiFile);
getManager().getFileManager().setViewProvider(getVirtualFile(), this);
}
static final class Template extends MultipleRootsInjectedFileViewProvider implements TemplateLanguageFileViewProvider {
Template(@NotNull PsiManagerEx psiManager,
@NotNull VirtualFileWindow virtualFile,
@NotNull DocumentWindowImpl documentWindow,
@NotNull Language language,
AbstractFileViewProvider original) {
super(psiManager, virtualFile, documentWindow, language, original);
assert myOriginalProvider instanceof TemplateLanguageFileViewProvider;
}
@NotNull
@Override
public Language getTemplateDataLanguage() {
return ((TemplateLanguageFileViewProvider)myOriginalProvider).getTemplateDataLanguage();
}
@Override
public IElementType getContentElementType(Language language, PsiFile file) {
return ((TemplateLanguageFileViewProvider)myOriginalProvider).getContentElementType(language, file);
}
}
}
@@ -0,0 +1,89 @@
/*
* Copyright 2000-2015 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.psi.impl.source.tree.injected;
import com.intellij.injected.editor.VirtualFileWindow;
import com.intellij.lang.Language;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.SingleRootFileViewProvider;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public class SingleRootInjectedFileViewProvider extends SingleRootFileViewProvider implements InjectedFileViewProvider {
private final Object myLock = new Object();
private final DocumentWindowImpl myDocumentWindow;
private boolean myPatchingLeaves;
SingleRootInjectedFileViewProvider(@NotNull PsiManager psiManager,
@NotNull VirtualFileWindow virtualFile,
@NotNull DocumentWindowImpl documentWindow,
@NotNull Language language) {
super(psiManager, (VirtualFile)virtualFile, true, language);
myDocumentWindow = documentWindow;
}
@Override
public Object getLock() {
return myLock;
}
@Override
public void setPatchingLeaves(boolean value) {
myPatchingLeaves = value;
}
@Override
public boolean getPatchingLeaves() {
return myPatchingLeaves;
}
@Override
public FileViewProvider clone() {
return cloneImpl();
}
@Override
public void rootChanged(@NotNull PsiFile psiFile) {
super.rootChanged(psiFile);
rootChangedImpl(psiFile);
}
@Override
public boolean isEventSystemEnabled() {
return isEventSystemEnabledImpl();
}
@Override
public boolean isPhysical() {
return isPhysicalImpl();
}
@Override
@NotNull
public DocumentWindowImpl getDocument() {
return myDocumentWindow;
}
@NonNls
@Override
public String toString() {
return "Single root injected file '"+getVirtualFile().getName()+"' " + (isValid() ? "" : " invalid") + (isPhysical() ? "" : " nonphysical");
}
}