use of com.intellij.injected.editor.DocumentWindowImpl in project intellij-community by JetBrains.
the class GenerationNode method generate.
@NotNull
public TemplateImpl generate(@NotNull CustomTemplateCallback callback, @Nullable ZenCodingGenerator generator, @NotNull Collection<ZenCodingFilter> filters, boolean insertSurroundedText, int segmentsLimit) {
myContainsSurroundedTextMarker = !(insertSurroundedText && myInsertSurroundedTextAtTheEnd);
GenerationNode generationNode = this;
if (generationNode != this) {
return generationNode.generate(callback, generator, Collections.emptyList(), insertSurroundedText, segmentsLimit);
}
boolean shouldNotReformatTemplate = false;
boolean oneLineTemplateExpanding = false;
for (ZenCodingFilter filter : filters) {
generationNode = filter.filterNode(generationNode);
if (filter instanceof SingleLineEmmetFilter) {
shouldNotReformatTemplate = true;
oneLineTemplateExpanding = true;
}
}
CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(callback.getProject());
String indentStr;
if (callback.isInInjectedFragment()) {
Editor editor = callback.getEditor();
Document document = editor.getDocument();
if (document instanceof DocumentWindowImpl && ((DocumentWindowImpl) document).isOneLine()) {
/*
* If document is one-line that in the moment of inserting text,
* new line chars will be filtered (see DocumentWindowImpl#insertString).
* So in this case we should filter text by SingleLineAvoid in order to avoid
* inconsistency of template segments.
*/
oneLineTemplateExpanding = true;
filters.add(new SingleLineEmmetFilter());
}
indentStr = "";
} else if (settings.useTabCharacter(callback.getFileType())) {
indentStr = "\t";
} else {
int tabSize = settings.getTabSize(callback.getFileType());
indentStr = StringUtil.repeatSymbol(' ', tabSize);
}
LiveTemplateBuilder builder = new LiveTemplateBuilder(EmmetOptions.getInstance().isAddEditPointAtTheEndOfTemplate(), segmentsLimit);
int end = -1;
boolean hasChildren = myChildren.size() > 0;
TemplateImpl parentTemplate;
Map<String, String> predefinedValues;
if (generator instanceof XmlZenCodingGenerator) {
TemplateToken xmlTemplateToken = myTemplateToken;
parentTemplate = invokeXmlTemplate(xmlTemplateToken, callback, generator, hasChildren);
predefinedValues = buildPredefinedValues(xmlTemplateToken.getAttributes(), (XmlZenCodingGenerator) generator, hasChildren);
} else {
parentTemplate = invokeTemplate(myTemplateToken, hasChildren, callback, generator);
predefinedValues = null;
}
String s = parentTemplate.getString();
for (ZenCodingFilter filter : filters) {
s = filter.filterText(s, myTemplateToken);
}
parentTemplate = parentTemplate.copy();
parentTemplate.setString(s);
final String txt = hasChildren || myContainsSurroundedTextMarker ? null : mySurroundedText;
parentTemplate = expandTemplate(parentTemplate, predefinedValues, txt, segmentsLimit);
int offset = builder.insertTemplate(0, parentTemplate, null);
int newOffset = gotoChild(callback.getProject(), builder.getText(), offset, 0, builder.length());
if (offset < builder.length() && newOffset != offset) {
end = offset;
}
offset = newOffset;
if (end == -1 && offset < builder.length() && myChildren.size() == 0) {
end = offset;
}
LiveTemplateBuilder.Marker marker = offset < builder.length() ? builder.createMarker(offset) : null;
//noinspection ForLoopReplaceableByForEach
for (int i = 0, myChildrenSize = myChildren.size(); i < myChildrenSize; i++) {
GenerationNode child = myChildren.get(i);
TemplateImpl childTemplate = child.generate(callback, generator, filters, !myContainsSurroundedTextMarker, segmentsLimit);
boolean blockTag = child.isBlockTag();
if (!oneLineTemplateExpanding && blockTag && !isNewLineBefore(builder.getText(), offset)) {
builder.insertText(offset, "\n" + indentStr, false);
offset += indentStr.length() + 1;
}
int e = builder.insertTemplate(offset, childTemplate, null);
offset = marker != null ? marker.getEndOffset() : builder.length();
if (!oneLineTemplateExpanding && ((blockTag && !isNewLineAfter(builder.getText(), offset)) || myInsertNewLineBetweenNodes)) {
builder.insertText(offset, "\n" + indentStr, false);
offset += indentStr.length() + 1;
}
if (end == -1 && e < offset) {
end = e;
}
}
if (shouldNotReformatTemplate) {
builder.setIsToReformat(false);
}
return builder.buildTemplate();
}
use of com.intellij.injected.editor.DocumentWindowImpl in project intellij-community by JetBrains.
the class InjectedFileViewProvider method clone.
@Override
public FileViewProvider clone() {
final DocumentWindow oldDocumentWindow = ((VirtualFileWindow) getVirtualFile()).getDocumentWindow();
Document hostDocument = oldDocumentWindow.getDelegate();
final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(getManager().getProject());
PsiFile hostFile = documentManager.getPsiFile(hostDocument);
Language language = getBaseLanguage();
PsiFile file = getPsi(language);
final Language hostFileLanguage = InjectedLanguageManager.getInstance(file.getProject()).getTopLevelFile(file).getLanguage();
PsiFile hostPsiFileCopy = (PsiFile) hostFile.copy();
Segment firstTextRange = oldDocumentWindow.getHostRanges()[0];
PsiElement hostElementCopy = hostPsiFileCopy.getViewProvider().findElementAt(firstTextRange.getStartOffset(), hostFileLanguage);
assert hostElementCopy != null;
final Ref<FileViewProvider> provider = new Ref<>();
PsiLanguageInjectionHost.InjectedPsiVisitor visitor = new PsiLanguageInjectionHost.InjectedPsiVisitor() {
@Override
public void visit(@NotNull PsiFile injectedPsi, @NotNull List<PsiLanguageInjectionHost.Shred> places) {
Document document = documentManager.getCachedDocument(injectedPsi);
if (document instanceof DocumentWindowImpl && oldDocumentWindow.areRangesEqual((DocumentWindowImpl) document)) {
provider.set(injectedPsi.getViewProvider());
}
}
};
for (PsiElement current = hostElementCopy; current != null && current != hostPsiFileCopy; current = current.getParent()) {
current.putUserData(LANGUAGE_FOR_INJECTED_COPY_KEY, language);
try {
InjectedLanguageUtil.enumerate(current, hostPsiFileCopy, false, visitor);
} finally {
current.putUserData(LANGUAGE_FOR_INJECTED_COPY_KEY, null);
}
if (provider.get() != null)
break;
}
return provider.get();
}
use of com.intellij.injected.editor.DocumentWindowImpl in project intellij-community by JetBrains.
the class MultiHostRegistrarImpl method freezeWindow.
@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);
}
use of com.intellij.injected.editor.DocumentWindowImpl in project intellij-community by JetBrains.
the class MultiHostRegistrarImpl method registerDocument.
// 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) {
List<DocumentWindow> injected = InjectedLanguageUtil.getCachedInjectedDocuments(hostPsiFile);
for (int i = injected.size() - 1; i >= 0; i--) {
DocumentWindowImpl oldDocument = (DocumentWindowImpl) injected.get(i);
final PsiFileImpl oldFile = (PsiFileImpl) documentManager.getCachedPsiFile(oldDocument);
FileViewProvider viewProvider;
if (oldFile == null || !oldFile.isValid() || !((viewProvider = oldFile.getViewProvider()) instanceof InjectedFileViewProvider) || ((InjectedFileViewProvider) viewProvider).isDisposed()) {
injected.remove(i);
Disposer.dispose(oldDocument);
continue;
}
InjectedFileViewProvider oldViewProvider = (InjectedFileViewProvider) viewProvider;
final ASTNode injectedNode = injectedPsi.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()) {
injected.remove(i);
Disposer.dispose(oldDocument);
continue;
}
oldFile.putUserData(FileContextUtil.INJECTED_IN_ELEMENT, injectedPsi.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();
}
});
}
assert shreds.isValid();
return oldFile;
}
}
injected.add(documentWindow);
return injectedPsi;
}
use of com.intellij.injected.editor.DocumentWindowImpl in project intellij-community by JetBrains.
the class MultiHostRegistrarImpl method doneInjecting.
@Override
public void doneInjecting() {
try {
if (shreds.isEmpty()) {
throw new IllegalStateException("Seems you haven't called addPlace()");
}
if (myReferenceInjector != null) {
addToResults(new Place(shreds), null);
return;
}
PsiDocumentManagerBase documentManager = (PsiDocumentManagerBase) PsiDocumentManager.getInstance(myProject);
Place place = new Place(shreds);
DocumentWindowImpl documentWindow = new DocumentWindowImpl(myHostDocument, isOneLineEditor, place);
String fileName = PathUtil.makeFileName(myHostVirtualFile.getName(), fileExtension);
VirtualFileWindowImpl virtualFile = new VirtualFileWindowImpl(fileName, myHostVirtualFile, documentWindow, myLanguage, outChars);
Language forcedLanguage = myContextElement.getUserData(InjectedFileViewProvider.LANGUAGE_FOR_INJECTED_COPY_KEY);
myLanguage = forcedLanguage == null ? LanguageSubstitutors.INSTANCE.substituteLanguage(myLanguage, virtualFile, myProject) : forcedLanguage;
createDocument(virtualFile);
InjectedFileViewProvider viewProvider = new InjectedFileViewProvider(myPsiManager, virtualFile, documentWindow, myLanguage);
ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(myLanguage);
assert parserDefinition != null : "Parser definition for language " + myLanguage + " is null";
PsiFile psiFile = parserDefinition.createFile(viewProvider);
SmartPsiElementPointer<PsiLanguageInjectionHost> pointer = ((ShredImpl) shreds.get(0)).getSmartPointer();
synchronized (InjectedLanguageManagerImpl.ourInjectionPsiLock) {
final ASTNode parsedNode = keepTreeFromChameleoningBack(psiFile);
assert parsedNode instanceof FileElement : "Parsed to " + parsedNode + " instead of FileElement";
String documentText = documentManager.getLastCommittedDocument(documentWindow).getText();
assert ((FileElement) parsedNode).textMatches(outChars) : exceptionContext("Before patch: doc:\n'" + documentText + "'\n---PSI:\n'" + parsedNode.getText() + "'\n---chars:\n'" + outChars + "'");
viewProvider.setPatchingLeaves(true);
try {
patchLeaves(parsedNode, escapers, place);
} catch (ProcessCanceledException e) {
throw e;
} catch (RuntimeException e) {
throw new RuntimeException(exceptionContext("Patch error"), e);
} finally {
viewProvider.setPatchingLeaves(false);
}
if (!((FileElement) parsedNode).textMatches(documentText)) {
throw new AssertionError(exceptionContext("After patch: doc:\n'" + documentText + "'\n---PSI:\n'" + parsedNode.getText() + "'\n---chars:\n'" + outChars + "'"));
}
virtualFile.setContent(null, documentWindow.getText(), false);
virtualFile.setWritable(virtualFile.getDelegate().isWritable());
cacheEverything(place, documentWindow, viewProvider, psiFile, pointer);
PsiFile cachedPsiFile = documentManager.getCachedPsiFile(documentWindow);
assert cachedPsiFile == psiFile : "Cached psi :" + cachedPsiFile + " instead of " + psiFile;
assert place.isValid();
assert viewProvider.isValid();
PsiFile newFile = registerDocument(documentWindow, psiFile, place, myHostPsiFile, documentManager);
boolean mergeHappened = newFile != psiFile;
if (mergeHappened) {
InjectedLanguageUtil.clearCaches(psiFile, documentWindow);
psiFile = newFile;
viewProvider = (InjectedFileViewProvider) psiFile.getViewProvider();
documentWindow = (DocumentWindowImpl) viewProvider.getDocument();
virtualFile = (VirtualFileWindowImpl) viewProvider.getVirtualFile();
boolean shredsRewritten = cacheEverything(place, documentWindow, viewProvider, psiFile, pointer);
if (!shredsRewritten) {
place.dispose();
place = documentWindow.getShreds();
}
}
assert psiFile.isValid();
assert place.isValid();
assert viewProvider.isValid();
try {
List<Trinity<IElementType, SmartPsiElementPointer<PsiLanguageInjectionHost>, TextRange>> tokens = obtainHighlightTokensFromLexer(myLanguage, outChars, escapers, place, virtualFile, myProject);
psiFile.putUserData(InjectedLanguageUtil.HIGHLIGHT_TOKENS, tokens);
} catch (ProcessCanceledException e) {
throw e;
} catch (RuntimeException e) {
throw new RuntimeException(exceptionContext("Obtaining tokens error"), e);
}
addToResults(place, psiFile);
assertEverythingIsAllright(documentManager, documentWindow, psiFile);
}
} finally {
clear();
}
}
Aggregations