@NotNull public PsiFile getPsiFileForPsiDependentIndex() { Document document = FileDocumentManager.getInstance().getCachedDocument(getFile()); PsiFile psi = null; if (document != null) { PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(getProject()); if (psiDocumentManager.isUncommited(document)) { PsiFile existingPsi = psiDocumentManager.getPsiFile(document); if (existingPsi != null) { psi = existingPsi; } } } if (psi == null) { psi = getPsiFile(); } return psi; }
/** * Inspects all lines of the given document and wraps all of them that exceed {@link * CodeStyleSettings#RIGHT_MARGIN right margin}. * * <p>I.e. the algorithm is to do the following for every line: * * <p> * * <pre> * <ol> * <li> * Check if the line exceeds {@link CodeStyleSettings#RIGHT_MARGIN right margin}. Go to the next line in the case of * negative answer; * </li> * <li>Determine line wrap position; </li> * <li> * Perform 'smart wrap', i.e. not only wrap the line but insert additional characters over than line feed if necessary. * For example consider that we wrap a single-line comment - we need to insert comment symbols on a start of the wrapped * part as well. Generally, we get the same behavior as during pressing 'Enter' at wrap position during editing document; * </li> * </ol> * </pre> * * @param file file that holds parsed document tree * @param document target document * @param startOffset start offset of the first line to check for wrapping (inclusive) * @param endOffset end offset of the first line to check for wrapping (exclusive) */ private void wrapLongLinesIfNecessary( @NotNull final PsiFile file, @Nullable final Document document, final int startOffset, final int endOffset) { if (!mySettings.getCommonSettings(file.getLanguage()).WRAP_LONG_LINES || PostprocessReformattingAspect.getInstance(file.getProject()) .isViewProviderLocked(file.getViewProvider()) || document == null) { return; } final VirtualFile vFile = FileDocumentManager.getInstance().getFile(document); if ((vFile == null || vFile instanceof LightVirtualFile) && !ApplicationManager.getApplication().isUnitTestMode()) { // we assume that control flow reaches this place when the document is backed by a "virtual" // file so any changes made by // a formatter affect only PSI and it is out of sync with a document text return; } Editor editor = PsiUtilBase.findEditor(file); EditorFactory editorFactory = null; if (editor == null) { if (!ApplicationManager.getApplication().isDispatchThread()) { return; } editorFactory = EditorFactory.getInstance(); editor = editorFactory.createEditor(document, file.getProject()); } try { final Editor editorToUse = editor; ApplicationManager.getApplication() .runWriteAction( new Runnable() { @Override public void run() { final CaretModel caretModel = editorToUse.getCaretModel(); final int caretOffset = caretModel.getOffset(); final RangeMarker caretMarker = editorToUse.getDocument().createRangeMarker(caretOffset, caretOffset); doWrapLongLinesIfNecessary( editorToUse, file.getProject(), editorToUse.getDocument(), startOffset, endOffset); if (caretMarker.isValid() && caretModel.getOffset() != caretMarker.getStartOffset()) { caretModel.moveToOffset(caretMarker.getStartOffset()); } } }); } finally { PsiDocumentManager documentManager = PsiDocumentManager.getInstance(file.getProject()); if (documentManager.isUncommited(document)) documentManager.commitDocument(document); if (editorFactory != null) { editorFactory.releaseEditor(editor); } } }
public static boolean canUseDocumentModel(@NotNull Document document, @NotNull PsiFile file) { PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(file.getProject()); return !psiDocumentManager.isUncommited(document) && !psiDocumentManager.isDocumentBlockedByPsi(document) && file.getText().equals(document.getText()); }
@Override public void startRunInjectors(@NotNull final Document hostDocument, final boolean synchronously) { if (myProject.isDisposed()) return; if (!synchronously && ApplicationManager.getApplication().isWriteAccessAllowed()) return; // use cached to avoid recreate PSI in alien project final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject); final PsiFile hostPsiFile = documentManager.getCachedPsiFile(hostDocument); if (hostPsiFile == null) return; final ConcurrentList<DocumentWindow> injected = InjectedLanguageUtil.getCachedInjectedDocuments(hostPsiFile); if (injected.isEmpty()) return; if (myProgress.isCanceled()) { myProgress = new DaemonProgressIndicator(); } final Set<DocumentWindow> newDocuments = Collections.synchronizedSet(new THashSet<>()); final Processor<DocumentWindow> commitProcessor = documentWindow -> { if (myProject.isDisposed()) return false; ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); if (indicator != null && indicator.isCanceled()) return false; if (documentManager.isUncommited(hostDocument) || !hostPsiFile.isValid()) return false; // will be committed later // it is here where the reparse happens and old file contents replaced InjectedLanguageUtil.enumerate( documentWindow, hostPsiFile, (injectedPsi, places) -> { DocumentWindow newDocument = (DocumentWindow) injectedPsi.getViewProvider().getDocument(); if (newDocument != null) { PsiDocumentManagerBase.checkConsistency(injectedPsi, newDocument); newDocuments.add(newDocument); } }); return true; }; final Runnable commitInjectionsRunnable = () -> { if (myProgress.isCanceled()) return; JobLauncher.getInstance() .invokeConcurrentlyUnderProgress( new ArrayList<>(injected), myProgress, true, commitProcessor); synchronized (ourInjectionPsiLock) { injected.clear(); injected.addAll(newDocuments); } }; if (synchronously) { if (Thread.holdsLock(PsiLock.LOCK)) { // hack for the case when docCommit was called from within PSI modification, e.g. in // formatter. // we can't spawn threads to do injections there, otherwise a deadlock is imminent ContainerUtil.process(new ArrayList<>(injected), commitProcessor); } else { commitInjectionsRunnable.run(); } } else { JobLauncher.getInstance() .submitToJobThread( () -> ApplicationManagerEx.getApplicationEx() .tryRunReadAction(commitInjectionsRunnable), null); } }