diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedFileViewProvider.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedFileViewProvider.java index 32063bbcb44d..6252cbc715fa 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedFileViewProvider.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedFileViewProvider.java @@ -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 disabledTemporarily = ThreadLocal.withInitial(() -> false); - private boolean myPatchingLeaves; - protected final AbstractFileViewProvider myOriginalProvider; +public interface InjectedFileViewProvider extends FileViewProvider, FreeThreadedFileViewProvider { + Key LANGUAGE_FOR_INJECTED_COPY_KEY = Key.create("LANGUAGE_FOR_INJECTED_COPY_KEY"); + ThreadLocal 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 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_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 getLanguages() { - FileViewProvider original = myOriginalProvider; - Set 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); } } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectionRegistrarImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectionRegistrarImpl.java index 7a7b1a6fe35b..e0e553aaa452 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectionRegistrarImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectionRegistrarImpl.java @@ -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 oldFiles = oldInjectedPsiViewProvider.getCachedPsiFiles(); + List oldFiles = ((AbstractFileViewProvider)oldInjectedPsiViewProvider).getCachedPsiFiles(); synchronized (InjectedLanguageManagerImpl.ourInjectionPsiLock) { DiffLog[] diffLogs = new DiffLog[parsedNodes.length]; for (int i = 0; i < parsedNodes.length; i++) { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultipleRootsInjectedFileViewProvider.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultipleRootsInjectedFileViewProvider.java new file mode 100644 index 000000000000..d0e2c345b92c --- /dev/null +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultipleRootsInjectedFileViewProvider.java @@ -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 getLanguages() { + FileViewProvider original = myOriginalProvider; + Set 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); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/SingleRootInjectedFileViewProvider.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/SingleRootInjectedFileViewProvider.java new file mode 100644 index 000000000000..bfd34f320325 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/SingleRootInjectedFileViewProvider.java @@ -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"); + } +}