Search in sources :

Example 1 with DocumentWindowImpl

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();
}
Also used : TemplateImpl(com.intellij.codeInsight.template.impl.TemplateImpl) XmlZenCodingGenerator(com.intellij.codeInsight.template.emmet.generators.XmlZenCodingGenerator) SingleLineEmmetFilter(com.intellij.codeInsight.template.emmet.filters.SingleLineEmmetFilter) Document(com.intellij.openapi.editor.Document) ZenCodingFilter(com.intellij.codeInsight.template.emmet.filters.ZenCodingFilter) CodeStyleSettings(com.intellij.psi.codeStyle.CodeStyleSettings) DocumentWindowImpl(com.intellij.injected.editor.DocumentWindowImpl) TemplateToken(com.intellij.codeInsight.template.emmet.tokens.TemplateToken) Editor(com.intellij.openapi.editor.Editor) LiveTemplateBuilder(com.intellij.codeInsight.template.LiveTemplateBuilder) NotNull(org.jetbrains.annotations.NotNull)

Example 2 with DocumentWindowImpl

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();
}
Also used : VirtualFileWindow(com.intellij.injected.editor.VirtualFileWindow) Document(com.intellij.openapi.editor.Document) NotNull(org.jetbrains.annotations.NotNull) Segment(com.intellij.openapi.util.Segment) DocumentWindow(com.intellij.injected.editor.DocumentWindow) Ref(com.intellij.openapi.util.Ref) Language(com.intellij.lang.Language) FreeThreadedFileViewProvider(com.intellij.psi.impl.FreeThreadedFileViewProvider) DocumentWindowImpl(com.intellij.injected.editor.DocumentWindowImpl) List(java.util.List)

Example 3 with DocumentWindowImpl

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);
}
Also used : DocumentEx(com.intellij.openapi.editor.ex.DocumentEx) Language(com.intellij.lang.Language) com.intellij.openapi.util(com.intellij.openapi.util) VirtualFileWindow(com.intellij.injected.editor.VirtualFileWindow) PsiFileImpl(com.intellij.psi.impl.source.PsiFileImpl) TreeElement(com.intellij.psi.impl.source.tree.TreeElement) SmartPointerManagerImpl(com.intellij.psi.impl.smartPointers.SmartPointerManagerImpl) IElementType(com.intellij.psi.tree.IElementType) VirtualFile(com.intellij.openapi.vfs.VirtualFile) NonNls(org.jetbrains.annotations.NonNls) ContainerUtil(com.intellij.util.containers.ContainerUtil) BlockSupportImpl(com.intellij.psi.impl.source.text.BlockSupportImpl) ArrayList(java.util.ArrayList) FileContextUtil(com.intellij.psi.impl.source.resolve.FileContextUtil) ProcessCanceledException(com.intellij.openapi.progress.ProcessCanceledException) PsiTreeUtil(com.intellij.psi.util.PsiTreeUtil) SyntaxHighlighter(com.intellij.openapi.fileTypes.SyntaxHighlighter) SmartList(com.intellij.util.SmartList) Map(java.util.Map) Project(com.intellij.openapi.project.Project) DocumentEx(com.intellij.openapi.editor.ex.DocumentEx) SyntaxHighlighterFactory(com.intellij.openapi.fileTypes.SyntaxHighlighterFactory) DocumentImpl(com.intellij.openapi.editor.impl.DocumentImpl) MultiHostRegistrar(com.intellij.lang.injection.MultiHostRegistrar) LightVirtualFile(com.intellij.testFramework.LightVirtualFile) Lexer(com.intellij.lexer.Lexer) DebugUtil(com.intellij.psi.impl.DebugUtil) DiffLog(com.intellij.psi.impl.source.text.DiffLog) DocumentWindow(com.intellij.injected.editor.DocumentWindow) StringUtil(com.intellij.openapi.util.text.StringUtil) DocumentWindowImpl(com.intellij.injected.editor.DocumentWindowImpl) TreeUtil(com.intellij.psi.impl.source.tree.TreeUtil) FileElement(com.intellij.psi.impl.source.tree.FileElement) ReferenceInjector(com.intellij.psi.injection.ReferenceInjector) FileDocumentManagerImpl(com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl) ASTNode(com.intellij.lang.ASTNode) ParserDefinition(com.intellij.lang.ParserDefinition) DocumentCommitThread(com.intellij.psi.impl.DocumentCommitThread) Nullable(org.jetbrains.annotations.Nullable) List(java.util.List) PsiUtilCore(com.intellij.psi.util.PsiUtilCore) PsiDocumentManagerBase(com.intellij.psi.impl.PsiDocumentManagerBase) LeafElement(com.intellij.psi.impl.source.tree.LeafElement) DaemonProgressIndicator(com.intellij.codeInsight.daemon.impl.DaemonProgressIndicator) LanguageParserDefinitions(com.intellij.lang.LanguageParserDefinitions) com.intellij.psi(com.intellij.psi) PathUtil(com.intellij.util.PathUtil) NotNull(org.jetbrains.annotations.NotNull) VirtualFileWindowImpl(com.intellij.injected.editor.VirtualFileWindowImpl) Project(com.intellij.openapi.project.Project) DocumentWindowImpl(com.intellij.injected.editor.DocumentWindowImpl) PsiDocumentManagerBase(com.intellij.psi.impl.PsiDocumentManagerBase) NotNull(org.jetbrains.annotations.NotNull)

Example 4 with DocumentWindowImpl

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;
}
Also used : DocumentWindow(com.intellij.injected.editor.DocumentWindow) DaemonProgressIndicator(com.intellij.codeInsight.daemon.impl.DaemonProgressIndicator) DocumentWindowImpl(com.intellij.injected.editor.DocumentWindowImpl) PsiFileImpl(com.intellij.psi.impl.source.PsiFileImpl) ASTNode(com.intellij.lang.ASTNode) DiffLog(com.intellij.psi.impl.source.text.DiffLog)

Example 5 with DocumentWindowImpl

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();
    }
}
Also used : VirtualFileWindowImpl(com.intellij.injected.editor.VirtualFileWindowImpl) PsiDocumentManagerBase(com.intellij.psi.impl.PsiDocumentManagerBase) ParserDefinition(com.intellij.lang.ParserDefinition) DocumentWindowImpl(com.intellij.injected.editor.DocumentWindowImpl) Language(com.intellij.lang.Language) ASTNode(com.intellij.lang.ASTNode) FileElement(com.intellij.psi.impl.source.tree.FileElement) ProcessCanceledException(com.intellij.openapi.progress.ProcessCanceledException)

Aggregations

DocumentWindowImpl (com.intellij.injected.editor.DocumentWindowImpl)10 Document (com.intellij.openapi.editor.Document)5 NotNull (org.jetbrains.annotations.NotNull)5 DocumentWindow (com.intellij.injected.editor.DocumentWindow)3 ASTNode (com.intellij.lang.ASTNode)3 Language (com.intellij.lang.Language)3 DaemonProgressIndicator (com.intellij.codeInsight.daemon.impl.DaemonProgressIndicator)2 VirtualFileWindow (com.intellij.injected.editor.VirtualFileWindow)2 VirtualFileWindowImpl (com.intellij.injected.editor.VirtualFileWindowImpl)2 ParserDefinition (com.intellij.lang.ParserDefinition)2 ProcessCanceledException (com.intellij.openapi.progress.ProcessCanceledException)2 Segment (com.intellij.openapi.util.Segment)2 TextRange (com.intellij.openapi.util.TextRange)2 PsiDocumentManagerBase (com.intellij.psi.impl.PsiDocumentManagerBase)2 PsiFileImpl (com.intellij.psi.impl.source.PsiFileImpl)2 DiffLog (com.intellij.psi.impl.source.text.DiffLog)2 FileElement (com.intellij.psi.impl.source.tree.FileElement)2 List (java.util.List)2 LiveTemplateBuilder (com.intellij.codeInsight.template.LiveTemplateBuilder)1 SingleLineEmmetFilter (com.intellij.codeInsight.template.emmet.filters.SingleLineEmmetFilter)1