mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
removed ugly dirty unsafe hacks
This commit is contained in:
@@ -107,4 +107,6 @@ public abstract class InjectedLanguageManager {
|
||||
* (which don't work for uncommitted document).
|
||||
*/
|
||||
public abstract boolean mightHaveInjectedFragmentAtOffset(@NotNull Document hostDocument, int hostOffset);
|
||||
@NotNull
|
||||
public abstract DocumentWindow freezeWindow(@NotNull DocumentWindow document);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,14 @@ import com.intellij.openapi.util.TextRange;
|
||||
|
||||
public interface MultiHostRegistrar {
|
||||
@NotNull /*this*/ MultiHostRegistrar startInjecting(@NotNull Language language);
|
||||
|
||||
/**
|
||||
* @param extension The injected file name will have this extension. Some parsers require extension. By default the extension is taken from the host file.
|
||||
*/
|
||||
@NotNull
|
||||
default /*this*/ MultiHostRegistrar startInjecting(@NotNull Language language, @Nullable String extension) {
|
||||
return startInjecting(language);
|
||||
}
|
||||
@NotNull /*this*/ MultiHostRegistrar addPlace(@NonNls @Nullable String prefix, @NonNls @Nullable String suffix, @NotNull PsiLanguageInjectionHost host, @NotNull TextRange rangeInsideHost);
|
||||
void doneInjecting();
|
||||
}
|
||||
@@ -19,8 +19,8 @@ package com.intellij.psi.impl;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
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.lang.injection.InjectedLanguageManager;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.application.TransactionGuard;
|
||||
@@ -43,7 +43,6 @@ 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;
|
||||
@@ -206,6 +205,6 @@ public class PsiDocumentManagerImpl extends PsiDocumentManagerBase implements Se
|
||||
@NotNull
|
||||
@Override
|
||||
protected DocumentWindow freezeWindow(@NotNull DocumentWindow document) {
|
||||
return MultiHostRegistrarImpl.freezeWindow((DocumentWindowImpl)document);
|
||||
return InjectedLanguageManager.getInstance(myProject).freezeWindow(document);
|
||||
}
|
||||
}
|
||||
|
||||
+15
-1
@@ -32,6 +32,7 @@ import com.intellij.openapi.application.ex.ApplicationManagerEx;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.ex.DocumentEx;
|
||||
import com.intellij.openapi.extensions.ExtensionPoint;
|
||||
import com.intellij.openapi.extensions.ExtensionPointListener;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
@@ -41,7 +42,10 @@ import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
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.PsiDocumentManagerBase;
|
||||
@@ -400,6 +404,16 @@ public class InjectedLanguageManagerImpl extends InjectedLanguageManager impleme
|
||||
return InjectedLanguageUtil.mightHaveInjectedFragmentAtCaret(myProject, hostDocument, hostOffset);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DocumentWindow freezeWindow(@NotNull DocumentWindow document) {
|
||||
Place shreds = ((DocumentWindowImpl)document).getShreds();
|
||||
Project project = shreds.getHostPointer().getProject();
|
||||
DocumentEx delegate = ((PsiDocumentManagerBase)PsiDocumentManager.getInstance(project)).getLastCommittedDocument(document.getDelegate());
|
||||
Place place = new Place(ContainerUtil.map(shreds, shred -> ((ShredImpl) shred).withPsiRange()));
|
||||
return new DocumentWindowImpl(delegate, ((DocumentWindowImpl)document).isOneLine(), place);
|
||||
}
|
||||
|
||||
private static int appendRange(@NotNull List<TextRange> result, int start, int length) {
|
||||
if (length > 0) {
|
||||
int lastIndex = result.size() - 1;
|
||||
|
||||
+34
-7
@@ -22,6 +22,7 @@ import com.intellij.lang.Language;
|
||||
import com.intellij.lang.LanguageUtil;
|
||||
import com.intellij.lang.injection.InjectedLanguageManager;
|
||||
import com.intellij.lang.injection.MultiHostRegistrar;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Caret;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
@@ -52,8 +53,8 @@ import java.util.List;
|
||||
* @author cdr
|
||||
*/
|
||||
public class InjectedLanguageUtil {
|
||||
static final Key<List<Trinity<IElementType, SmartPsiElementPointer<PsiLanguageInjectionHost>, TextRange>>> HIGHLIGHT_TOKENS =
|
||||
Key.create("HIGHLIGHT_TOKENS");
|
||||
private static final Logger LOG = Logger.getInstance(InjectedLanguageUtil.class);
|
||||
static final Key<List<Trinity<IElementType, SmartPsiElementPointer<PsiLanguageInjectionHost>, TextRange>>> HIGHLIGHT_TOKENS = Key.create("HIGHLIGHT_TOKENS");
|
||||
public static final Key<IElementType> INJECTED_FRAGMENT_TYPE = Key.create("INJECTED_FRAGMENT_TYPE");
|
||||
public static final Key<Boolean> FRANKENSTEIN_INJECTION = InjectedLanguageManager.FRANKENSTEIN_INJECTION;
|
||||
// meaning: injected file text is probably incorrect
|
||||
@@ -648,13 +649,39 @@ public class InjectedLanguageUtil {
|
||||
getShreds(((VirtualFileWindow)virtualFile).getDocumentWindow()).getHostPointer().getElement() : null;
|
||||
}
|
||||
|
||||
public static <T> void putInjectedFileUserData(MultiHostRegistrar registrar, Key<T> key, T value) {
|
||||
PsiFile psiFile = getInjectedFile(registrar);
|
||||
if (psiFile != null) psiFile.putUserData(key, value);
|
||||
public static <T> void putInjectedFileUserData(@NotNull PsiElement element,
|
||||
@NotNull Language language,
|
||||
@NotNull Key<T> key,
|
||||
T value) {
|
||||
PsiFile file = getCachedInjectedFileWithLanguage(element, language);
|
||||
if (file != null) {
|
||||
file.putUserData(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static PsiFile getInjectedFile(MultiHostRegistrar registrar) {
|
||||
/**
|
||||
* @deprecated use {@link #putInjectedFileUserData(com.intellij.psi.PsiElement, com.intellij.lang.Language, com.intellij.openapi.util.Key, java.lang.Object)} instead
|
||||
*/
|
||||
public static <T> void putInjectedFileUserData(MultiHostRegistrar registrar, Key<T> key, T value) {
|
||||
LOG.warn("use #putInjectedFileUserData(com.intellij.psi.PsiElement, com.intellij.lang.Language, com.intellij.openapi.util.Key, java.lang.Object)} instead");
|
||||
final List<Pair<Place,PsiFile>> result = ((MultiHostRegistrarImpl)registrar).getResult();
|
||||
return result == null || result.isEmpty() ? null : result.get(result.size() - 1).second;
|
||||
if (result != null && !result.isEmpty()) {
|
||||
PsiFile file = result.get(result.size() - 1).getSecond();
|
||||
file.putUserData(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiFile getCachedInjectedFileWithLanguage(@NotNull PsiElement element, @NotNull Language language) {
|
||||
if (!element.isValid()) return null;
|
||||
PsiFile containingFile = element.getContainingFile();
|
||||
if (containingFile == null || !containingFile.isValid()) return null;
|
||||
return InjectedLanguageManager.getInstance(containingFile.getProject())
|
||||
.getCachedInjectedDocumentsInRange(containingFile, element.getTextRange())
|
||||
.stream()
|
||||
.map(documentWindow -> PsiDocumentManager.getInstance(containingFile.getProject()).getPsiFile(documentWindow))
|
||||
.filter(file -> file != null && file.getLanguage() == language)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
+51
-63
@@ -57,7 +57,6 @@ import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.testFramework.LightVirtualFile;
|
||||
import com.intellij.util.PathUtil;
|
||||
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;
|
||||
@@ -66,10 +65,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author cdr
|
||||
*/
|
||||
public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationTracker {
|
||||
class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationTracker {
|
||||
private List<Pair<Place, PsiFile>> result;
|
||||
private Language myLanguage;
|
||||
private List<LiteralTextEscaper<? extends PsiLanguageInjectionHost>> escapers;
|
||||
@@ -86,9 +82,7 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
|
||||
private final PsiFile myHostPsiFile;
|
||||
private ReferenceInjector myReferenceInjector;
|
||||
|
||||
public MultiHostRegistrarImpl(@NotNull Project project,
|
||||
@NotNull PsiFile hostPsiFile,
|
||||
@NotNull PsiElement contextElement) {
|
||||
MultiHostRegistrarImpl(@NotNull Project project, @NotNull PsiFile hostPsiFile, @NotNull PsiElement contextElement) {
|
||||
myProject = project;
|
||||
myContextElement = contextElement;
|
||||
myHostPsiFile = PsiUtilCore.getTemplateLanguageFile(hostPsiFile);
|
||||
@@ -99,18 +93,21 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
|
||||
myHostDocument = (DocumentEx)viewProvider.getDocument();
|
||||
}
|
||||
|
||||
public List<Pair<Place, PsiFile>> getResult() {
|
||||
@Nullable("null means nobody cared to call .doneInjecting()")
|
||||
List<Pair<Place, PsiFile>> getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiElement getContextElement() {
|
||||
return myContextElement;
|
||||
@Override
|
||||
public MultiHostRegistrar startInjecting(@NotNull Language language) {
|
||||
return startInjecting(language, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public MultiHostRegistrar startInjecting(@NotNull Language language) {
|
||||
@Override
|
||||
public MultiHostRegistrar startInjecting(@NotNull Language language, @Nullable String extension) {
|
||||
fileExtension = extension;
|
||||
escapers = new SmartList<>();
|
||||
shreds = new SmartList<>();
|
||||
outChars = new StringBuilder();
|
||||
@@ -129,9 +126,6 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
|
||||
myReferenceInjector = injector;
|
||||
}
|
||||
myLanguage = language;
|
||||
// todo uncomment
|
||||
//LanguageFileType fileType = myLanguage.getAssociatedFileType();
|
||||
//fileExtension = fileType == null ? null : fileType.getDefaultExtension();
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -146,10 +140,6 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
|
||||
cleared = true;
|
||||
}
|
||||
|
||||
public void setFileExtension(@Nullable String fileExtension) {
|
||||
this.fileExtension = fileExtension;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public MultiHostRegistrar addPlace(@NonNls @Nullable String prefix,
|
||||
@@ -306,12 +296,10 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static DocumentEx createDocument(@NotNull LightVirtualFile virtualFile) {
|
||||
private static void createDocument(@NotNull LightVirtualFile virtualFile) {
|
||||
CharSequence content = virtualFile.getContent();
|
||||
DocumentImpl document = new DocumentImpl(content, StringUtil.indexOf(content, '\r') >= 0, false);
|
||||
FileDocumentManagerImpl.registerDocument(document, virtualFile);
|
||||
return document;
|
||||
}
|
||||
|
||||
// returns true if shreds were set, false if old ones were reused
|
||||
@@ -388,12 +376,12 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
|
||||
PsiDocumentManagerBase.checkConsistency(psiFile, frozenWindow);
|
||||
}
|
||||
|
||||
public void addToResults(Place place, PsiFile psiFile, @NotNull MultiHostRegistrarImpl from) {
|
||||
void addToResults(@NotNull Place place, @Nullable /*WAT?*/PsiFile psiFile, @NotNull MultiHostRegistrarImpl from) {
|
||||
addToResults(place, psiFile);
|
||||
myReferenceInjector = from.myReferenceInjector;
|
||||
}
|
||||
|
||||
private void addToResults(Place place, PsiFile psiFile) {
|
||||
private void addToResults(@NotNull Place place, @Nullable /*WAT?*/PsiFile psiFile) {
|
||||
if (result == null) {
|
||||
result = new SmartList<>();
|
||||
}
|
||||
@@ -430,12 +418,13 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
|
||||
TreeUtil.clearCaches((TreeElement)parsedNode);
|
||||
}
|
||||
|
||||
// under com.intellij.psi.PsiLock.LOCK
|
||||
private static PsiFile registerDocument(final DocumentWindowImpl documentWindow,
|
||||
final PsiFile injectedPsi,
|
||||
final Place shreds,
|
||||
final PsiFile hostPsiFile,
|
||||
final PsiDocumentManager documentManager) {
|
||||
// under InjectedLanguageManagerImpl.ourInjectionPsiLock
|
||||
@NotNull
|
||||
private static PsiFile registerDocument(@NotNull DocumentWindowImpl newDocumentWindow,
|
||||
@NotNull PsiFile newInjectedPsi,
|
||||
@NotNull Place shreds,
|
||||
@NotNull PsiFile hostPsiFile,
|
||||
@NotNull PsiDocumentManager documentManager) {
|
||||
List<DocumentWindow> injected = InjectedLanguageUtil.getCachedInjectedDocuments(hostPsiFile);
|
||||
|
||||
for (int i = injected.size()-1; i>=0; i--) {
|
||||
@@ -451,44 +440,51 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
|
||||
Disposer.dispose(oldDocument);
|
||||
continue;
|
||||
}
|
||||
InjectedFileViewProvider oldViewProvider = (InjectedFileViewProvider)viewProvider;
|
||||
|
||||
final ASTNode injectedNode = injectedPsi.getNode();
|
||||
final ASTNode newInjectedNode = newInjectedPsi.getNode();
|
||||
final ASTNode oldFileNode = oldFile.getNode();
|
||||
assert injectedNode != null : "New node is null";
|
||||
if (oldDocument.areRangesEqual(documentWindow)) {
|
||||
if (oldFile.getFileType() != injectedPsi.getFileType() || oldFile.getLanguage() != injectedPsi.getLanguage()) {
|
||||
assert newInjectedNode != null : "New node is null";
|
||||
if (oldDocument.areRangesEqual(newDocumentWindow)) {
|
||||
if (oldFile.getFileType() != newInjectedPsi.getFileType() || oldFile.getLanguage() != newInjectedPsi.getLanguage()) {
|
||||
injected.remove(i);
|
||||
Disposer.dispose(oldDocument);
|
||||
continue;
|
||||
}
|
||||
oldFile.putUserData(FileContextUtil.INJECTED_IN_ELEMENT, injectedPsi.getUserData(FileContextUtil.INJECTED_IN_ELEMENT));
|
||||
oldFile.putUserData(FileContextUtil.INJECTED_IN_ELEMENT, newInjectedPsi.getUserData(FileContextUtil.INJECTED_IN_ELEMENT));
|
||||
|
||||
assert shreds.isValid();
|
||||
if (!oldFile.textMatches(injectedPsi)) {
|
||||
oldViewProvider.performNonPhysically(() -> {
|
||||
DebugUtil.startPsiModification("injected tree diff");
|
||||
try {
|
||||
final DiffLog diffLog = BlockSupportImpl.mergeTrees(oldFile, oldFileNode, injectedNode, new DaemonProgressIndicator(),
|
||||
oldFileNode.getText());
|
||||
DocumentCommitThread.doActualPsiChange(oldFile, diffLog);
|
||||
}
|
||||
finally {
|
||||
DebugUtil.finishPsiModification();
|
||||
}
|
||||
});
|
||||
}
|
||||
mergePsi(oldFile, oldFileNode, newInjectedPsi, newInjectedNode);
|
||||
assert shreds.isValid();
|
||||
|
||||
return oldFile;
|
||||
}
|
||||
else if (intersect(oldDocument, documentWindow)) {
|
||||
else if (intersect(oldDocument, newDocumentWindow)) {
|
||||
injected.remove(i); // injected fragments should not overlap. In the End, there can be only one.
|
||||
}
|
||||
}
|
||||
injected.add(documentWindow);
|
||||
injected.add(newDocumentWindow);
|
||||
|
||||
return injectedPsi;
|
||||
return newInjectedPsi;
|
||||
}
|
||||
|
||||
private static void mergePsi(@NotNull PsiFileImpl oldFile,
|
||||
@NotNull ASTNode oldFileNode,
|
||||
@NotNull PsiFile injectedPsi,
|
||||
@NotNull ASTNode injectedNode) {
|
||||
if (!oldFile.textMatches(injectedPsi)) {
|
||||
InjectedFileViewProvider oldViewProvider = (InjectedFileViewProvider)oldFile.getViewProvider();
|
||||
oldViewProvider.performNonPhysically(() -> {
|
||||
DebugUtil.startPsiModification("injected tree diff");
|
||||
try {
|
||||
final DiffLog diffLog = BlockSupportImpl.mergeTrees(oldFile, oldFileNode, injectedNode, new DaemonProgressIndicator(),
|
||||
oldFileNode.getText());
|
||||
DocumentCommitThread.doActualPsiChange(oldFile, diffLog);
|
||||
}
|
||||
finally {
|
||||
DebugUtil.finishPsiModification();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean intersect(DocumentWindowImpl doc1, DocumentWindowImpl doc2) {
|
||||
@@ -583,8 +579,9 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
|
||||
return String.valueOf(result);
|
||||
}
|
||||
|
||||
// performance: avoid context.getContainingFile()
|
||||
@NotNull
|
||||
public PsiFile getHostPsiFile() {
|
||||
PsiFile getHostPsiFile() {
|
||||
return myHostPsiFile;
|
||||
}
|
||||
|
||||
@@ -592,15 +589,6 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT
|
||||
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, shred -> ((ShredImpl) shred).withPsiRange()));
|
||||
return new DocumentWindowImpl(delegate, window.isOneLine(), place);
|
||||
}
|
||||
|
||||
boolean isValid() {
|
||||
List<Pair<Place, PsiFile>> result = getResult();
|
||||
if (result == null) return false;
|
||||
|
||||
+38
-30
@@ -19,6 +19,7 @@ import com.intellij.lang.Language;
|
||||
import com.intellij.lang.injection.ConcatenationAwareInjector;
|
||||
import com.intellij.lang.injection.MultiHostRegistrar;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.Trinity;
|
||||
@@ -31,6 +32,7 @@ import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import gnu.trove.THashSet;
|
||||
import org.intellij.plugins.intelliLang.Configuration;
|
||||
import org.intellij.plugins.intelliLang.inject.InjectedLanguage;
|
||||
@@ -88,13 +90,15 @@ public class ConcatenationInjector implements ConcatenationAwareInjector {
|
||||
PsiFile finalContainingFile = containingFile;
|
||||
InjectionProcessor injectionProcessor = new InjectionProcessor(myConfiguration, mySupport, operands) {
|
||||
@Override
|
||||
protected void processInjection(Language language,
|
||||
List<Trinity<PsiLanguageInjectionHost, InjectedLanguage, TextRange>> list,
|
||||
boolean settingsAvailable,
|
||||
boolean unparsable) {
|
||||
protected Pair<PsiLanguageInjectionHost, Language> processInjection(Language language,
|
||||
List<Trinity<PsiLanguageInjectionHost, InjectedLanguage, TextRange>> list,
|
||||
boolean settingsAvailable,
|
||||
boolean unparsable) {
|
||||
InjectorUtils.registerInjection(language, list, finalContainingFile, registrar);
|
||||
InjectorUtils.registerSupport(mySupport, settingsAvailable, registrar);
|
||||
InjectorUtils.putInjectedFileUserData(registrar, InjectedLanguageUtil.FRANKENSTEIN_INJECTION, unparsable ? Boolean.TRUE : null);
|
||||
InjectorUtils.registerSupport(mySupport, settingsAvailable, list.get(0).getFirst(), language);
|
||||
PsiLanguageInjectionHost host = list.get(0).getFirst();
|
||||
InjectorUtils.putInjectedFileUserData(host, language, InjectedLanguageUtil.FRANKENSTEIN_INJECTION, unparsable ? Boolean.TRUE : null);
|
||||
return Pair.create(host,language);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -112,8 +116,12 @@ public class ConcatenationInjector implements ConcatenationAwareInjector {
|
||||
if (tempLanguage != null) {
|
||||
BaseInjection baseInjection = new BaseInjection(JavaLanguageInjectionSupport.JAVA_SUPPORT_ID);
|
||||
baseInjection.setInjectedLanguageId(tempInjectedLanguage.getID());
|
||||
injectionProcessor.processInjectionInner(baseInjection, false);
|
||||
InjectorUtils.putInjectedFileUserData(registrar, LanguageInjectionSupport.TEMPORARY_INJECTED_LANGUAGE, tempInjectedLanguage);
|
||||
List<Pair<PsiLanguageInjectionHost, Language>> list = injectionProcessor.processInjectionWithContext(baseInjection, false);
|
||||
for (Pair<PsiLanguageInjectionHost, Language> pair : list) {
|
||||
PsiLanguageInjectionHost host = pair.getFirst();
|
||||
Language language = pair.getSecond();
|
||||
InjectorUtils.putInjectedFileUserData(host, language, LanguageInjectionSupport.TEMPORARY_INJECTED_LANGUAGE, tempInjectedLanguage);
|
||||
}
|
||||
}
|
||||
else {
|
||||
injectionProcessor.processInjections();
|
||||
@@ -333,28 +341,24 @@ public class ConcatenationInjector implements ConcatenationAwareInjector {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void processInjectionInner(BaseInjection injection, boolean settingsAvailable) {
|
||||
processInjectionWithContext(injection, settingsAvailable);
|
||||
}
|
||||
|
||||
private void processInjectionWithContext(BaseInjection injection, boolean settingsAvailable) {
|
||||
@NotNull
|
||||
List<Pair<PsiLanguageInjectionHost, Language>> processInjectionWithContext(BaseInjection injection, boolean settingsAvailable) {
|
||||
Language language = InjectorUtils.getLanguage(injection);
|
||||
if (language == null) return;
|
||||
if (language == null) return Collections.emptyList();
|
||||
|
||||
boolean separateFiles = !injection.isSingleFile() && StringUtil.isNotEmpty(injection.getValuePattern());
|
||||
|
||||
Ref<Boolean> unparsableRef = Ref.create(myUnparsable);
|
||||
List<Object> objects = ContextComputationProcessor.collectOperands(injection.getPrefix(), injection.getSuffix(), unparsableRef, myOperands);
|
||||
if (objects.isEmpty()) return;
|
||||
List<Trinity<PsiLanguageInjectionHost, InjectedLanguage, TextRange>> result =
|
||||
new ArrayList<>();
|
||||
if (objects.isEmpty()) return Collections.emptyList();
|
||||
List<Trinity<PsiLanguageInjectionHost, InjectedLanguage, TextRange>> result = new ArrayList<>();
|
||||
int len = objects.size();
|
||||
for (int i = 0; i < len; i++) {
|
||||
String curPrefix = null;
|
||||
Object o = objects.get(i);
|
||||
if (o instanceof String) {
|
||||
curPrefix = (String)o;
|
||||
if (i == len - 1) return; // IDEADEV-26751
|
||||
if (i == len - 1) return Collections.emptyList(); // IDEADEV-26751
|
||||
o = objects.get(++i);
|
||||
}
|
||||
String curSuffix = null;
|
||||
@@ -393,22 +397,26 @@ public class ConcatenationInjector implements ConcatenationAwareInjector {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!result.isEmpty()) {
|
||||
if (separateFiles) {
|
||||
for (Trinity<PsiLanguageInjectionHost, InjectedLanguage, TextRange> trinity : result) {
|
||||
processInjection(language, Collections.singletonList(trinity), settingsAvailable, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
processInjection(language, result, settingsAvailable, unparsableRef.get());
|
||||
if (result.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<Pair<PsiLanguageInjectionHost, Language>> res = new ArrayList<>();
|
||||
if (separateFiles) {
|
||||
for (Trinity<PsiLanguageInjectionHost, InjectedLanguage, TextRange> trinity : result) {
|
||||
ContainerUtil.addIfNotNull(res, processInjection(language, Collections.singletonList(trinity), settingsAvailable, false));
|
||||
}
|
||||
}
|
||||
else {
|
||||
ContainerUtil.addIfNotNull(res, processInjection(language, result, settingsAvailable, unparsableRef.get()));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
protected void processInjection(Language language,
|
||||
List<Trinity<PsiLanguageInjectionHost, InjectedLanguage, TextRange>> list,
|
||||
boolean xmlInjection,
|
||||
boolean unparsable) {
|
||||
protected Pair<PsiLanguageInjectionHost, Language> processInjection(Language language,
|
||||
List<Trinity<PsiLanguageInjectionHost, InjectedLanguage, TextRange>> list,
|
||||
boolean xmlInjection,
|
||||
boolean unparsable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected boolean areThereInjectionsWithName(String methodName, boolean annoOnly) {
|
||||
|
||||
+30
-10
@@ -19,16 +19,19 @@ package org.intellij.plugins.intelliLang.inject;
|
||||
import com.intellij.codeInsight.completion.CompletionUtil;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.injection.MultiHostRegistrar;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.FileTypeManager;
|
||||
import com.intellij.openapi.fileTypes.LanguageFileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.Trinity;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
|
||||
import com.intellij.psi.impl.source.tree.injected.MultiHostRegistrarImpl;
|
||||
import com.intellij.psi.injection.ReferenceInjector;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
@@ -55,6 +58,7 @@ import java.util.regex.Pattern;
|
||||
* @author Gregory.Shrago
|
||||
*/
|
||||
public class InjectorUtils {
|
||||
private static final Logger LOG = Logger.getInstance(InjectorUtils.class);
|
||||
public static final Comparator<TextRange> RANGE_COMPARATOR = (o1, o2) -> {
|
||||
if (o1.intersects(o2)) return 0;
|
||||
return o1.getStartOffset() - o2.getStartOffset();
|
||||
@@ -99,7 +103,7 @@ public class InjectorUtils {
|
||||
//}
|
||||
registerInjection(language, list, host.getContainingFile(), registrar);
|
||||
if (support != null) {
|
||||
registerSupport(support, true, registrar);
|
||||
registerSupport(support, true, host, language);
|
||||
}
|
||||
return !ranges.isEmpty();
|
||||
}
|
||||
@@ -122,10 +126,12 @@ public class InjectorUtils {
|
||||
InjectedLanguage injectedLanguage = t.second;
|
||||
|
||||
if (!injectionStarted) {
|
||||
registrar.startInjecting(language);
|
||||
// TextMate language requires file extension
|
||||
if (registrar instanceof MultiHostRegistrarImpl && !StringUtil.equalsIgnoreCase(language.getID(), t.second.getID())) {
|
||||
((MultiHostRegistrarImpl)registrar).setFileExtension(StringUtil.toLowerCase(t.second.getID()));
|
||||
if (!StringUtil.equalsIgnoreCase(language.getID(), t.second.getID())) {
|
||||
registrar.startInjecting(language, StringUtil.toLowerCase(t.second.getID()));
|
||||
}
|
||||
else {
|
||||
registrar.startInjecting(language);
|
||||
}
|
||||
injectionStarted = true;
|
||||
}
|
||||
@@ -219,19 +225,33 @@ public class InjectorUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void registerSupport(@NotNull LanguageInjectionSupport support, boolean settingsAvailable, @NotNull PsiElement element, @NotNull Language language) {
|
||||
putInjectedFileUserData(element, language, LanguageInjectionSupport.INJECTOR_SUPPORT, support);
|
||||
if (settingsAvailable) {
|
||||
putInjectedFileUserData(element, language, LanguageInjectionSupport.SETTINGS_EDITOR, support);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link InjectorUtils#registerSupport(org.intellij.plugins.intelliLang.inject.LanguageInjectionSupport, boolean, com.intellij.psi.PsiElement, com.intellij.lang.Language)} instead
|
||||
*/
|
||||
public static void registerSupport(@NotNull LanguageInjectionSupport support, boolean settingsAvailable, @NotNull MultiHostRegistrar registrar) {
|
||||
LOG.warn("use {@link InjectorUtils#registerSupport(org.intellij.plugins.intelliLang.inject.LanguageInjectionSupport, boolean, com.intellij.psi.PsiElement, com.intellij.lang.Language)} instead");
|
||||
putInjectedFileUserData(registrar, LanguageInjectionSupport.INJECTOR_SUPPORT, support);
|
||||
if (settingsAvailable) {
|
||||
putInjectedFileUserData(registrar, LanguageInjectionSupport.SETTINGS_EDITOR, support);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> void putInjectedFileUserData(MultiHostRegistrar registrar, Key<T> key, T value) {
|
||||
InjectedLanguageUtil.putInjectedFileUserData(registrar, key, value);
|
||||
public static <T> void putInjectedFileUserData(@NotNull PsiElement element, @NotNull Language language, Key<T> key, T value) {
|
||||
InjectedLanguageUtil.putInjectedFileUserData(element, language, key, value);
|
||||
}
|
||||
|
||||
public static PsiFile getInjectedFile(MultiHostRegistrar registrar) {
|
||||
return InjectedLanguageUtil.getInjectedFile(registrar);
|
||||
/**
|
||||
* @deprecated use {@link InjectorUtils#putInjectedFileUserData(com.intellij.psi.PsiElement, com.intellij.lang.Language, com.intellij.openapi.util.Key, java.lang.Object)} instead
|
||||
*/
|
||||
public static <T> void putInjectedFileUserData(MultiHostRegistrar registrar, Key<T> key, T value) {
|
||||
InjectedLanguageUtil.putInjectedFileUserData(registrar, key, value);
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedParameters")
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ public class TemporaryPlacesInjector implements MultiHostInjector {
|
||||
List<Trinity<PsiLanguageInjectionHost, InjectedLanguage,TextRange>> trinities =
|
||||
Collections.singletonList(Trinity.create(host, injectedLanguage, manipulator.getRangeInElement(host)));
|
||||
InjectorUtils.registerInjection(language, trinities, containingFile, registrar);
|
||||
InjectorUtils.registerSupport(myRegistry.getLanguageInjectionSupport(), false, registrar);
|
||||
InjectorUtils.registerSupport(myRegistry.getLanguageInjectionSupport(), false, context, language);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -89,9 +89,9 @@ public final class XmlLanguageInjector implements MultiHostInjector {
|
||||
ranges.add(textRange.shiftRight(host1.getTextRange().getStartOffset()));
|
||||
}
|
||||
InjectorUtils.registerInjection(language, list, containingFile, registrar);
|
||||
InjectorUtils.registerSupport(mySupport, true, registrar);
|
||||
InjectorUtils.registerSupport(mySupport, true, list.get(0).getFirst(), language);
|
||||
if (Boolean.TRUE.equals(unparsableRef.get())) {
|
||||
InjectorUtils.putInjectedFileUserData(registrar, InjectedLanguageUtil.FRANKENSTEIN_INJECTION, Boolean.TRUE);
|
||||
InjectorUtils.putInjectedFileUserData(host, language, InjectedLanguageUtil.FRANKENSTEIN_INJECTION, Boolean.TRUE);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
+2
-2
@@ -84,8 +84,8 @@ public class GrConcatenationAwareInjector implements ConcatenationAwareInjector
|
||||
boolean settingsAvailable,
|
||||
boolean unparsable) {
|
||||
InjectorUtils.registerInjection(language, list, file, registrar);
|
||||
InjectorUtils.registerSupport(mySupport, settingsAvailable, registrar);
|
||||
InjectorUtils.putInjectedFileUserData(registrar, InjectedLanguageUtil.FRANKENSTEIN_INJECTION, unparsable);
|
||||
InjectorUtils.registerSupport(mySupport, settingsAvailable, list.get(0).getFirst(), language);
|
||||
InjectorUtils.putInjectedFileUserData(list.get(0).getFirst(), language, InjectedLanguageUtil.FRANKENSTEIN_INJECTION, unparsable);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ public class PyConfigurationInjector extends PyInjectorBase {
|
||||
public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context) {
|
||||
final PyInjectionUtil.InjectionResult result = registerInjection(registrar, context);
|
||||
if (!result.isStrict()) {
|
||||
InjectorUtils.putInjectedFileUserData(registrar, InjectedLanguageUtil.FRANKENSTEIN_INJECTION, Boolean.TRUE);
|
||||
InjectorUtils.putInjectedFileUserData(context, getInjectedLanguage(context), InjectedLanguageUtil.FRANKENSTEIN_INJECTION, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -38,9 +38,9 @@ public class PyTemporaryInjector extends PyInjectorBase {
|
||||
final PyInjectionUtil.InjectionResult result = registerInjection(registrar, context);
|
||||
if (result.isInjected()) {
|
||||
final TemporaryPlacesRegistry registry = TemporaryPlacesRegistry.getInstance(context.getProject());
|
||||
InjectorUtils.registerSupport(registry.getLanguageInjectionSupport(), false, registrar);
|
||||
InjectorUtils.registerSupport(registry.getLanguageInjectionSupport(), false, context, getInjectedLanguage(context));
|
||||
if (!result.isStrict()) {
|
||||
InjectorUtils.putInjectedFileUserData(registrar, InjectedLanguageUtil.FRANKENSTEIN_INJECTION, Boolean.TRUE);
|
||||
InjectorUtils.putInjectedFileUserData(context, getInjectedLanguage(context), InjectedLanguageUtil.FRANKENSTEIN_INJECTION, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,9 @@ package com.jetbrains.python.codeInsight.regexp;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.injection.MultiHostInjector;
|
||||
import com.intellij.lang.injection.MultiHostRegistrar;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
|
||||
import com.intellij.psi.impl.source.tree.injected.MultiHostRegistrarImpl;
|
||||
import com.intellij.psi.impl.source.tree.injected.Place;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.jetbrains.python.codeInsight.PyInjectionUtil;
|
||||
@@ -104,7 +101,7 @@ public class PythonRegexpInjector implements MultiHostInjector {
|
||||
if (result.isInjected()) {
|
||||
registrar.doneInjecting();
|
||||
if (!result.isStrict()) {
|
||||
final PsiFile file = getInjectedFile(registrar);
|
||||
final PsiFile file = InjectedLanguageUtil.getCachedInjectedFileWithLanguage(context, language);
|
||||
if (file != null) {
|
||||
file.putUserData(InjectedLanguageUtil.FRANKENSTEIN_INJECTION, Boolean.TRUE);
|
||||
}
|
||||
@@ -112,13 +109,6 @@ public class PythonRegexpInjector implements MultiHostInjector {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiFile getInjectedFile(@NotNull MultiHostRegistrar registrar) {
|
||||
// Don't add a dependency on IntelliLang here now, but this injector should become IntelliLang-based in the future
|
||||
final List<Pair<Place, PsiFile>> result = ((MultiHostRegistrarImpl)registrar).getResult();
|
||||
return result == null || result.isEmpty() ? null : result.get(result.size() - 1).second;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<? extends Class<? extends PsiElement>> elementsToInjectIn() {
|
||||
|
||||
Reference in New Issue
Block a user