@Override @SuppressWarnings({"CloneDoesntDeclareCloneNotSupportedException", "CloneDoesntCallSuperClone"}) protected PsiFileImpl clone() { FileViewProvider viewProvider = getViewProvider(); FileViewProvider providerCopy = viewProvider.clone(); final Language language = getLanguage(); if (providerCopy == null) { throw new AssertionError( "Unable to clone the view provider: " + viewProvider + "; " + language); } PsiFileImpl clone = BlockSupportImpl.getFileCopy(this, providerCopy); copyCopyableDataTo(clone); if (getTreeElement() != null) { // not set by provider in clone final FileElement treeClone = (FileElement) calcTreeElement().clone(); clone.setTreeElementPointer( treeClone); // should not use setTreeElement here because cloned file still have // VirtualFile (SCR17963) treeClone.setPsi(clone); } if (viewProvider.isEventSystemEnabled()) { clone.myOriginalFile = this; } else if (myOriginalFile != null) { clone.myOriginalFile = myOriginalFile; } return clone; }
@Override public void beforeDocumentChange(DocumentEvent event) { final Document document = event.getDocument(); final FileViewProvider viewProvider = getCachedViewProvider(document); if (viewProvider == null) return; if (!isRelevant(viewProvider)) return; VirtualFile virtualFile = viewProvider.getVirtualFile(); if (virtualFile.getFileType().isBinary()) return; final List<PsiFile> files = viewProvider.getAllFiles(); PsiFile psiCause = null; for (PsiFile file : files) { mySmartPointerManager.fastenBelts(file, event.getOffset(), null); if (TextBlock.get(file).isLocked()) { psiCause = file; } } if (psiCause == null) { beforeDocumentChangeOnUnlockedDocument(viewProvider); } ((SingleRootFileViewProvider) viewProvider).beforeDocumentChanged(psiCause); }
private void checkPsiIsCorrect(final FileViewProvider key) { PsiFile actualPsi = key.getPsi(key.getBaseLanguage()); PsiTreeDebugBuilder treeDebugBuilder = new PsiTreeDebugBuilder().setShowErrorElements(false).setShowWhiteSpaces(false); String actualPsiTree = treeDebugBuilder.psiToString(actualPsi); String fileName = key.getVirtualFile().getName(); PsiFile psi = PsiFileFactory.getInstance(myProject) .createFileFromText( fileName, FileTypeManager.getInstance().getFileTypeByFileName(fileName), actualPsi.getNode().getText(), LocalTimeCounter.currentTime(), false); if (actualPsi.getClass().equals(psi.getClass())) { String expectedPsi = treeDebugBuilder.psiToString(psi); if (!expectedPsi.equals(actualPsiTree)) { myReformatElements.clear(); assert expectedPsi.equals(actualPsiTree) : "Refactored psi should be the same as result of parsing"; } } }
protected boolean isPsiUpToDate(@NotNull VirtualFile vFile) { final FileViewProvider provider = myManager.findViewProvider(vFile); Language language = getLanguage(); if (provider == null || provider.getPsi(language) == this) { // provider == null in tests return true; } Language baseLanguage = provider.getBaseLanguage(); return baseLanguage != language && provider.getPsi(baseLanguage) == this; }
@Override public boolean isValid() { FileViewProvider provider = getViewProvider(); final VirtualFile vFile = provider.getVirtualFile(); if (!vFile.isValid()) return false; if (!provider.isEventSystemEnabled()) return true; // "dummy" file if (myManager.getProject().isDisposed()) return false; return isPsiUpToDate(vFile); }
private void doPostponedFormattingInner(final FileViewProvider key) { final List<ASTNode> astNodes = myReformatElements.remove(key); final Document document = key.getDocument(); // Sort ranges by end offsets so that we won't need any offset adjustment after reformat or // reindent if (document == null) return; final VirtualFile virtualFile = key.getVirtualFile(); if (!virtualFile.isValid()) return; final TreeSet<PostprocessFormattingTask> postProcessTasks = new TreeSet<PostprocessFormattingTask>(); Collection<Disposable> toDispose = ContainerUtilRt.newArrayList(); try { // process all roots in viewProvider to find marked for reformat before elements and create // appropriate range markers handleReformatMarkers(key, postProcessTasks); toDispose.addAll(postProcessTasks); // then we create ranges by changed nodes. One per node. There ranges can intersect. Ranges // are sorted by end offset. if (astNodes != null) createActionsMap(astNodes, key, postProcessTasks); if ("true".equals(System.getProperty("check.psi.is.valid")) && ApplicationManager.getApplication().isUnitTestMode()) { checkPsiIsCorrect(key); } while (!postProcessTasks.isEmpty()) { // now we have to normalize actions so that they not intersect and ordered in most // appropriate way // (free reformatting -> reindent -> formatting under reindent) final List<PostponedAction> normalizedActions = normalizeAndReorderPostponedActions(postProcessTasks, document); toDispose.addAll(normalizedActions); // only in following loop real changes in document are made for (final PostponedAction normalizedAction : normalizedActions) { CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(myPsiManager.getProject()); boolean old = settings.ENABLE_JAVADOC_FORMATTING; settings.ENABLE_JAVADOC_FORMATTING = false; try { normalizedAction.execute(key); } finally { settings.ENABLE_JAVADOC_FORMATTING = old; } } } } finally { for (Disposable disposable : toDispose) { //noinspection SSBasedInspection disposable.dispose(); } } }
@Override public void documentChanged(DocumentEvent event) { final Document document = event.getDocument(); final FileViewProvider viewProvider = getCachedViewProvider(document); if (viewProvider == null) return; if (!isRelevant(viewProvider)) return; ApplicationManager.getApplication().assertWriteAccessAllowed(); final List<PsiFile> files = viewProvider.getAllFiles(); boolean commitNecessary = true; for (PsiFile file : files) { mySmartPointerManager.unfastenBelts(file, event.getOffset()); final TextBlock textBlock = TextBlock.get(file); if (textBlock.isLocked()) { commitNecessary = false; continue; } textBlock.documentChanged(event); assert file instanceof PsiFileImpl || "mock.file".equals(file.getName()) && ApplicationManager.getApplication().isUnitTestMode() : event + "; file=" + file + "; allFiles=" + files + "; viewProvider=" + viewProvider; } boolean forceCommit = ApplicationManager.getApplication().hasWriteAction(ExternalChangeAction.class) && (SystemProperties.getBooleanProperty("idea.force.commit.on.external.change", false) || ApplicationManager.getApplication().isHeadlessEnvironment()); // Consider that it's worth to perform complete re-parse instead of merge if the whole document // text is replaced and // current document lines number is roughly above 5000. This makes sense in situations when // external change is performed // for the huge file (that causes the whole document to be reloaded and 'merge' way takes a // while to complete). if (event.isWholeTextReplaced() && document.getTextLength() > 100000) { document.putUserData(BlockSupport.DO_NOT_REPARSE_INCREMENTALLY, Boolean.TRUE); } if (commitNecessary) { myUncommittedDocuments.add(document); if (forceCommit) { commitDocument(document); } else if (!((DocumentEx) document).isInBulkUpdate()) { myDocumentCommitProcessor.commitAsynchronously(myProject, document, event); } } }
public void execute(FileViewProvider viewProvider) { final Document document = viewProvider.getDocument(); final PsiFile psiFile = viewProvider.getPsi(viewProvider.getBaseLanguage()); for (Pair<Integer, RangeMarker> integerRangeMarkerPair : myRangesToReindent) { RangeMarker marker = integerRangeMarkerPair.second; final CharSequence charsSequence = document.getCharsSequence().subSequence(marker.getStartOffset(), marker.getEndOffset()); final int oldIndent = integerRangeMarkerPair.first; final TextRange[] whitespaces = CharArrayUtil.getIndents(charsSequence, marker.getStartOffset()); final int indentAdjustment = getNewIndent(psiFile, marker.getStartOffset()) - oldIndent; if (indentAdjustment != 0) adjustIndentationInRange(psiFile, document, whitespaces, indentAdjustment); } }
private static void handleReformatMarkers( final FileViewProvider key, final TreeSet<PostprocessFormattingTask> rangesToProcess) { final Document document = key.getDocument(); if (document == null) { return; } for (final FileElement fileElement : ((SingleRootFileViewProvider) key).getKnownTreeRoots()) { fileElement.acceptTree( new RecursiveTreeElementWalkingVisitor() { protected void visitNode(TreeElement element) { if (CodeEditUtil.isMarkedToReformatBefore(element)) { CodeEditUtil.markToReformatBefore(element, false); rangesToProcess.add( new ReformatWithHeadingWhitespaceTask( document.createRangeMarker( element.getStartOffset(), element.getStartOffset()))); } else if (CodeEditUtil.isMarkedToReformat(element)) { CodeEditUtil.markToReformat(element, false); rangesToProcess.add( new ReformatWithHeadingWhitespaceTask( document.createRangeMarker( element.getStartOffset(), element.getStartOffset() + element.getTextLength()))); } super.visitNode(element); } }); } }
@Override public void visitFile(PsiFile file) { final VirtualFile virtualFile = file.getVirtualFile(); if (virtualFile != null) { String relative = ProjectUtilCore.displayUrlRelativeToProject( virtualFile, virtualFile.getPresentableUrl(), myProject, true, false); myContext.incrementJobDoneAmount(myContext.getStdJobDescriptors().BUILD_GRAPH, relative); } final FileViewProvider viewProvider = file.getViewProvider(); final Set<Language> relevantLanguages = viewProvider.getLanguages(); for (Language language : relevantLanguages) { visitElement(viewProvider.getPsi(language)); } myPsiManager.dropResolveCaches(); InjectedLanguageManager.getInstance(myProject).dropFileCaches(file); }
@Override public void beforeDocumentChange(@NotNull DocumentEvent event) { if (myStopTrackingDocuments) return; final Document document = event.getDocument(); if (!(document instanceof DocumentWindow) && !myLastCommittedTexts.containsKey(document)) { myLastCommittedTexts.put( document, Pair.create(document.getImmutableCharSequence(), document.getModificationStamp())); } VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document); boolean isRelevant = virtualFile != null && isRelevant(virtualFile); final FileViewProvider viewProvider = getCachedViewProvider(document); boolean inMyProject = viewProvider != null && viewProvider.getManager() == myPsiManager; if (!isRelevant || !inMyProject) { return; } final List<PsiFile> files = viewProvider.getAllFiles(); PsiFile psiCause = null; for (PsiFile file : files) { if (file == null) { throw new AssertionError( "View provider " + viewProvider + " (" + viewProvider.getClass() + ") returned null in its files array: " + files + " for file " + viewProvider.getVirtualFile()); } if (mySynchronizer.isInsideAtomicChange(file)) { psiCause = file; } } if (psiCause == null) { beforeDocumentChangeOnUnlockedDocument(viewProvider); } ((SingleRootFileViewProvider) viewProvider).beforeDocumentChanged(psiCause); }
@Nullable @Override public Document getDocument(@NotNull PsiFile file) { if (file instanceof PsiBinaryFile) return null; Document document = getCachedDocument(file); if (document != null) { if (!file.getViewProvider().isPhysical() && document.getUserData(HARD_REF_TO_PSI) == null) { PsiUtilCore.ensureValid(file); cachePsi(document, file); } return document; } FileViewProvider viewProvider = file.getViewProvider(); if (!viewProvider.isEventSystemEnabled()) return null; document = FileDocumentManager.getInstance().getDocument(viewProvider.getVirtualFile()); if (document != null) { if (document.getTextLength() != file.getTextLength()) { String message = "Document/PSI mismatch: " + file + " (" + file.getClass() + "); physical=" + viewProvider.isPhysical(); if (document.getTextLength() + file.getTextLength() < 8096) { message += "\n=== document ===\n" + document.getText() + "\n=== PSI ===\n" + file.getText(); } throw new AssertionError(message); } if (!viewProvider.isPhysical()) { PsiUtilCore.ensureValid(file); cachePsi(document, file); file.putUserData(HARD_REF_TO_DOCUMENT, document); } } return document; }
protected boolean finishCommitInWriteAction( @NotNull final Document document, @NotNull final List<Processor<Document>> finishProcessors, final boolean synchronously) { if (myProject.isDisposed()) return false; assert !(document instanceof DocumentWindow); myIsCommitInProgress = true; boolean success = true; try { final FileViewProvider viewProvider = getCachedViewProvider(document); if (viewProvider != null) { for (Processor<Document> finishRunnable : finishProcessors) { success = finishRunnable.process(document); if (synchronously) { assert success : finishRunnable + " in " + finishProcessors; } if (!success) { break; } } if (success) { myLastCommittedTexts.remove(document); viewProvider.contentsSynchronized(); } } else { handleCommitWithoutPsi(document); } } finally { myDocumentCommitProcessor.log( "in PDI.finishDoc: ", null, synchronously, success, myUncommittedDocuments); if (success) { myUncommittedDocuments.remove(document); myDocumentCommitProcessor.log( "in PDI.finishDoc: removed doc", null, synchronously, success, myUncommittedDocuments); } myIsCommitInProgress = false; myDocumentCommitProcessor.log( "in PDI.finishDoc: exit", null, synchronously, success, myUncommittedDocuments); } return success; }
private CodeFormatterFacade getFormatterFacade(final FileViewProvider viewProvider) { final CodeStyleSettings styleSettings = CodeStyleSettingsManager.getSettings(myPsiManager.getProject()); final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myPsiManager.getProject()); final Document document = viewProvider.getDocument(); final CodeFormatterFacade codeFormatter = new CodeFormatterFacade(styleSettings); documentManager.commitDocument(document); return codeFormatter; }
@Override @NotNull public PsiFile[] getPsiRoots() { final FileViewProvider viewProvider = getViewProvider(); final Set<Language> languages = viewProvider.getLanguages(); final PsiFile[] roots = new PsiFile[languages.size()]; int i = 0; for (Language language : languages) { PsiFile psi = viewProvider.getPsi(language); if (psi == null) { LOG.error("PSI is null for " + language + "; in file: " + this); } roots[i++] = psi; } if (roots.length > 1) { Arrays.sort(roots, FILE_BY_LANGUAGE_ID); } return roots; }
public void beforeDocumentChanged(@NotNull FileViewProvider viewProvider) { if (isViewProviderLocked(viewProvider)) { Throwable cause = viewProvider.getUserData(REFORMAT_ORIGINATOR); @NonNls String message = "Document is locked by write PSI operations. " + "Use PsiDocumentManager.doPostponedOperationsAndUnblockDocument() to commit PSI changes to the document." + (cause == null ? "" : " See cause stacktrace for the reason to lock."); throw cause == null ? new RuntimeException(message) : new RuntimeException(message, cause); } postponedFormatting(viewProvider); }
protected void reportStubAstMismatch(String message, StubTree stubTree, Document cachedDocument) { rebuildStub(); clearStub("stub-psi mismatch"); scheduleDropCachesWithInvalidStubPsi(); String msg = message; msg += "\n file=" + this; msg += ", modStamp=" + getModificationStamp(); msg += "\n stub debugInfo=" + stubTree.getDebugInfo(); msg += "\n document before=" + cachedDocument; ObjectStubTree latestIndexedStub = StubTreeLoader.getInstance().readFromVFile(getProject(), getVirtualFile()); msg += "\nlatestIndexedStub=" + latestIndexedStub; if (latestIndexedStub != null) { msg += "\n same size=" + (stubTree.getPlainList().size() == latestIndexedStub.getPlainList().size()); msg += "\n debugInfo=" + latestIndexedStub.getDebugInfo(); } FileViewProvider viewProvider = getViewProvider(); msg += "\n viewProvider=" + viewProvider; msg += "\n viewProvider stamp: " + viewProvider.getModificationStamp(); VirtualFile file = viewProvider.getVirtualFile(); msg += "; file stamp: " + file.getModificationStamp(); msg += "; file modCount: " + file.getModificationCount(); Document document = FileDocumentManager.getInstance().getCachedDocument(file); if (document != null) { msg += "\n doc saved: " + !FileDocumentManager.getInstance().isDocumentUnsaved(document); msg += "; doc stamp: " + document.getModificationStamp(); msg += "; doc size: " + document.getTextLength(); msg += "; committed: " + PsiDocumentManager.getInstance(getProject()).isCommitted(document); } throw new AssertionError(msg + "\n------------\n"); }
public void unloadContent() { ApplicationManager.getApplication().assertWriteAccessAllowed(); clearCaches(); myViewProvider.beforeContentsSynchronized(); synchronized (PsiLock.LOCK) { FileElement treeElement = derefTreeElement(); DebugUtil.startPsiModification("unloadContent"); try { if (treeElement != null) { myTreeElementPointer = null; treeElement.detachFromFile(); DebugUtil.onInvalidated(treeElement); } clearStub("unloadContent"); } finally { DebugUtil.finishPsiModification(); } } }
private void postponeFormatting(@NotNull FileViewProvider viewProvider, @NotNull ASTNode child) { if (!CodeEditUtil.isNodeGenerated(child) && child.getElementType() != TokenType.WHITE_SPACE) { final int oldIndent = CodeEditUtil.getOldIndentation(child); LOG.assertTrue( oldIndent >= 0, "for not generated items old indentation must be defined: element=" + child + ", text=" + child.getText()); } List<ASTNode> list = myReformatElements.get(viewProvider); if (list == null) { list = new ArrayList<ASTNode>(); myReformatElements.put(viewProvider, list); if (STORE_REFORMAT_ORIGINATOR_STACKTRACE) { viewProvider.putUserData(REFORMAT_ORIGINATOR, new Throwable()); } } list.add(child); }
@NotNull private FileElement loadTreeElement() { ApplicationManager.getApplication().assertReadAccessAllowed(); final FileViewProvider viewProvider = getViewProvider(); if (viewProvider.isPhysical() && myManager.isAssertOnFileLoading(viewProvider.getVirtualFile())) { LOG.error( "Access to tree elements not allowed in tests. path='" + viewProvider.getVirtualFile().getPresentableUrl() + "'"); } Document cachedDocument = FileDocumentManager.getInstance().getCachedDocument(getViewProvider().getVirtualFile()); FileElement treeElement = createFileElement(viewProvider.getContents()); treeElement.setPsi(this); List<Pair<StubBasedPsiElementBase, CompositeElement>> bindings = calcStubAstBindings(treeElement, cachedDocument); synchronized (PsiLock.LOCK) { FileElement existing = derefTreeElement(); if (existing != null) { return existing; } switchFromStubToAst(bindings); myStub = null; myTreeElementPointer = createTreeElementPointer(treeElement); if (LOG.isDebugEnabled() && viewProvider.isPhysical()) { LOG.debug("Loaded text for file " + viewProvider.getVirtualFile().getPresentableUrl()); } return treeElement; } }
private boolean isRelevant(@NotNull FileViewProvider viewProvider) { VirtualFile virtualFile = viewProvider.getVirtualFile(); return !virtualFile.getFileType().isBinary() && viewProvider.getManager() == myPsiManager && !myPsiManager.getProject().isDisposed(); }
private static void createActionsMap( @NotNull List<ASTNode> astNodes, @NotNull FileViewProvider provider, @NotNull final TreeSet<PostprocessFormattingTask> rangesToProcess) { final Set<ASTNode> nodesToProcess = new HashSet<ASTNode>(astNodes); final Document document = provider.getDocument(); if (document == null) { return; } for (final ASTNode node : astNodes) { nodesToProcess.remove(node); final FileElement fileElement = TreeUtil.getFileElement((TreeElement) node); if (fileElement == null || ((PsiFile) fileElement.getPsi()).getViewProvider() != provider) continue; final boolean isGenerated = CodeEditUtil.isNodeGenerated(node); ((TreeElement) node) .acceptTree( new RecursiveTreeElementVisitor() { boolean inGeneratedContext = !isGenerated; @Override protected boolean visitNode(TreeElement element) { if (nodesToProcess.contains(element)) return false; final boolean currentNodeGenerated = CodeEditUtil.isNodeGenerated(element); CodeEditUtil.setNodeGenerated(element, false); if (currentNodeGenerated && !inGeneratedContext) { rangesToProcess.add( new ReformatTask(document.createRangeMarker(element.getTextRange()))); inGeneratedContext = true; } if (!currentNodeGenerated && inGeneratedContext) { if (element.getElementType() == TokenType.WHITE_SPACE) return false; final int oldIndent = CodeEditUtil.getOldIndentation(element); CodeEditUtil.setOldIndentation(element, -1); LOG.assertTrue( oldIndent >= 0, "for not generated items old indentation must be defined: element " + element); for (TextRange indentRange : getEnabledRanges(element.getPsi())) { rangesToProcess.add( new ReindentTask(document.createRangeMarker(indentRange), oldIndent)); } inGeneratedContext = false; } return true; } private Iterable<TextRange> getEnabledRanges(@NotNull PsiElement element) { List<TextRange> disabledRanges = new ArrayList<TextRange>(); for (DisabledIndentRangesProvider rangesProvider : DisabledIndentRangesProvider.EP_NAME.getExtensions()) { Collection<TextRange> providedDisabledRanges = rangesProvider.getDisabledIndentRanges(element); if (providedDisabledRanges != null) { disabledRanges.addAll(providedDisabledRanges); } } return TextRangeUtil.excludeRanges(element.getTextRange(), disabledRanges); } @Override public void visitComposite(CompositeElement composite) { boolean oldGeneratedContext = inGeneratedContext; super.visitComposite(composite); inGeneratedContext = oldGeneratedContext; } @Override public void visitLeaf(LeafElement leaf) { boolean oldGeneratedContext = inGeneratedContext; super.visitLeaf(leaf); inGeneratedContext = oldGeneratedContext; } }); } }
@NotNull public static PsiElement[] findStatementsInRange( @NotNull PsiFile file, int startOffset, int endOffset) { Language language = findJavaOrLikeLanguage(file); if (language == null) return PsiElement.EMPTY_ARRAY; FileViewProvider viewProvider = file.getViewProvider(); PsiElement element1 = viewProvider.findElementAt(startOffset, language); PsiElement element2 = viewProvider.findElementAt(endOffset - 1, language); if (element1 instanceof PsiWhiteSpace) { startOffset = element1.getTextRange().getEndOffset(); element1 = file.findElementAt(startOffset); } if (element2 instanceof PsiWhiteSpace) { endOffset = element2.getTextRange().getStartOffset(); element2 = file.findElementAt(endOffset - 1); } if (element1 == null || element2 == null) return PsiElement.EMPTY_ARRAY; PsiElement parent = PsiTreeUtil.findCommonParent(element1, element2); if (parent == null) return PsiElement.EMPTY_ARRAY; while (true) { if (parent instanceof PsiStatement) { parent = parent.getParent(); break; } if (parent instanceof PsiCodeBlock) break; // if (JspPsiUtil.isInJspFile(parent) && parent instanceof PsiFile) break; if (parent instanceof PsiCodeFragment) break; if (parent == null || parent instanceof PsiFile) return PsiElement.EMPTY_ARRAY; parent = parent.getParent(); } if (!parent.equals(element1)) { while (!parent.equals(element1.getParent())) { element1 = element1.getParent(); } } if (startOffset != element1.getTextRange().getStartOffset()) return PsiElement.EMPTY_ARRAY; if (!parent.equals(element2)) { while (!parent.equals(element2.getParent())) { element2 = element2.getParent(); } } if (endOffset != element2.getTextRange().getEndOffset()) return PsiElement.EMPTY_ARRAY; if (parent instanceof PsiCodeBlock && parent.getParent() instanceof PsiBlockStatement && element1 == ((PsiCodeBlock) parent).getLBrace() && element2 == ((PsiCodeBlock) parent).getRBrace()) { return new PsiElement[] {parent.getParent()}; } /* if(parent instanceof PsiCodeBlock && parent.getParent() instanceof PsiBlockStatement) { return new PsiElement[]{parent.getParent()}; } */ PsiElement[] children = parent.getChildren(); ArrayList<PsiElement> array = new ArrayList<PsiElement>(); boolean flag = false; for (PsiElement child : children) { if (child.equals(element1)) { flag = true; } if (flag && !(child instanceof PsiWhiteSpace)) { array.add(child); } if (child.equals(element2)) { break; } } for (PsiElement element : array) { if (!(element instanceof PsiStatement || element instanceof PsiWhiteSpace || element instanceof PsiComment)) { return PsiElement.EMPTY_ARRAY; } } return PsiUtilCore.toPsiElementArray(array); }
@Override public void documentChanged(DocumentEvent event) { if (myStopTrackingDocuments) return; final Document document = event.getDocument(); VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document); boolean isRelevant = virtualFile != null && isRelevant(virtualFile); final FileViewProvider viewProvider = getCachedViewProvider(document); if (viewProvider == null) { handleCommitWithoutPsi(document); return; } boolean inMyProject = viewProvider.getManager() == myPsiManager; if (!isRelevant || !inMyProject) { myLastCommittedTexts.remove(document); return; } ApplicationManager.getApplication().assertWriteAccessAllowed(); final List<PsiFile> files = viewProvider.getAllFiles(); boolean commitNecessary = true; for (PsiFile file : files) { if (mySynchronizer.isInsideAtomicChange(file)) { commitNecessary = false; continue; } assert file instanceof PsiFileImpl || "mock.file".equals(file.getName()) && ApplicationManager.getApplication().isUnitTestMode() : event + "; file=" + file + "; allFiles=" + files + "; viewProvider=" + viewProvider; } boolean forceCommit = ApplicationManager.getApplication().hasWriteAction(ExternalChangeAction.class) && (SystemProperties.getBooleanProperty("idea.force.commit.on.external.change", false) || ApplicationManager.getApplication().isHeadlessEnvironment() && !ApplicationManager.getApplication().isUnitTestMode()); // Consider that it's worth to perform complete re-parse instead of merge if the whole document // text is replaced and // current document lines number is roughly above 5000. This makes sense in situations when // external change is performed // for the huge file (that causes the whole document to be reloaded and 'merge' way takes a // while to complete). if (event.isWholeTextReplaced() && document.getTextLength() > 100000) { document.putUserData(BlockSupport.DO_NOT_REPARSE_INCREMENTALLY, Boolean.TRUE); } if (commitNecessary) { assert !(document instanceof DocumentWindow); myUncommittedDocuments.add(document); myDocumentCommitProcessor.log( "added uncommitted doc", null, false, myProject, document, ((DocumentEx) document).isInBulkUpdate()); if (forceCommit) { commitDocument(document); } else if (!((DocumentEx) document).isInBulkUpdate() && myPerformBackgroundCommit) { myDocumentCommitProcessor.commitAsynchronously(myProject, document, event); } } else { myLastCommittedTexts.remove(document); } }
public void execute(FileViewProvider viewProvider) { final CodeFormatterFacade codeFormatter = getFormatterFacade(viewProvider); codeFormatter.processText( viewProvider.getPsi(viewProvider.getBaseLanguage()), myRanges.ensureNonEmpty(), false); }
private static void createActionsMap( final List<ASTNode> astNodes, final FileViewProvider provider, final TreeSet<PostprocessFormattingTask> rangesToProcess) { final Set<ASTNode> nodesToProcess = new HashSet<ASTNode>(astNodes); final Document document = provider.getDocument(); for (final ASTNode node : astNodes) { nodesToProcess.remove(node); final FileElement fileElement = TreeUtil.getFileElement((TreeElement) node); if (fileElement == null || ((PsiFile) fileElement.getPsi()).getViewProvider() != provider) continue; final boolean isGenerated = CodeEditUtil.isNodeGenerated(node); ((TreeElement) node) .acceptTree( new RecursiveTreeElementVisitor() { boolean inGeneratedContext = !isGenerated; protected boolean visitNode(TreeElement element) { if (nodesToProcess.contains(element)) return false; if (CodeEditUtil.isPostponedFormattingDisabled(element)) return false; final boolean currentNodeGenerated = CodeEditUtil.isNodeGenerated(element); CodeEditUtil.setNodeGenerated(element, false); if (currentNodeGenerated && !inGeneratedContext) { rangesToProcess.add( new ReformatTask(document.createRangeMarker(element.getTextRange()))); inGeneratedContext = true; } if (!currentNodeGenerated && inGeneratedContext) { if (element.getElementType() == TokenType.WHITE_SPACE) return false; final int oldIndent = CodeEditUtil.getOldIndentation(element); LOG.assertTrue( oldIndent >= 0, "for not generated items old indentation must be defined: element " + element); rangesToProcess.add( new ReindentTask( document.createRangeMarker(element.getTextRange()), oldIndent)); inGeneratedContext = false; } return true; } @Override public void visitComposite(CompositeElement composite) { boolean oldGeneratedContext = inGeneratedContext; super.visitComposite(composite); inGeneratedContext = oldGeneratedContext; } @Override public void visitLeaf(LeafElement leaf) { boolean oldGeneratedContext = inGeneratedContext; super.visitLeaf(leaf); inGeneratedContext = oldGeneratedContext; } }); CodeEditUtil.enablePostponedFormattingInTree(node); } }
protected PsiFileImpl(@NotNull FileViewProvider provider) { myManager = (PsiManagerEx) provider.getManager(); myViewProvider = provider; }