private void processVirtualFile(@Nonnull final VirtualFile vfile, @Nonnull final ProgressIndicator progress, @Nonnull final Processor<? super PsiFile> localProcessor, @Nonnull final AtomicBoolean canceled) throws ApplicationUtil.CannotRunReadActionException { final PsiFile file = ApplicationUtil.tryRunReadAction(() -> vfile.isValid() ? myManager.findFile(vfile) : null); if (file != null && !(file instanceof PsiBinaryFile)) { // load contents outside read action if (FileDocumentManager.getInstance().getCachedDocument(vfile) == null) { // cache bytes in vfs try { vfile.contentsToByteArray(); } catch (IOException ignored) { } } ApplicationUtil.tryRunReadAction(() -> { final Project project = myManager.getProject(); if (project.isDisposed()) throw new ProcessCanceledException(); if (DumbService.isDumb(project)) throw ApplicationUtil.CannotRunReadActionException.create(); List<PsiFile> psiRoots = file.getViewProvider().getAllFiles(); Set<PsiFile> processed = new THashSet<>(psiRoots.size() * 2, (float)0.5); for (final PsiFile psiRoot : psiRoots) { progress.checkCanceled(); assert psiRoot != null : "One of the roots of file " + file + " is null. All roots: " + psiRoots + "; ViewProvider: " + file.getViewProvider() + "; Virtual file: " + file.getViewProvider().getVirtualFile(); if (!processed.add(psiRoot)) continue; if (!psiRoot.isValid()) { continue; } if (!localProcessor.process(psiRoot)) { canceled.set(true); break; } } }); } }
/** * Executes a {@code runnable} in an "impatient" mode. * In this mode any attempt to grab read lock * will fail (i.e. throw {@link ApplicationUtil.CannotRunReadActionException}) * if there is a pending write lock request. */ void executeByImpatientReader(@Nonnull Runnable runnable) throws ApplicationUtil.CannotRunReadActionException { checkReadThreadAccess(); Reader status = R.get(); boolean old = status.impatientReads; try { status.impatientReads = true; runnable.run(); } finally { status.impatientReads = old; } }
/** * Executes a {@code runnable} in an "impatient" mode. * In this mode any attempt to call {@link #runReadAction(Runnable)} * would fail (i.e. throw {@link ApplicationUtil.CannotRunReadActionException}) * if there is a pending write action. */ public void executeByImpatientReader(@Nonnull Runnable runnable) throws ApplicationUtil.CannotRunReadActionException { if (isDispatchThread()) { runnable.run(); } else { myLock.executeByImpatientReader(runnable); } }
/** * @param files to scan for references in this pass. * @param totalSize the number of files to scan in both passes. Can be different from <code>files.size()</code> in case of * two-pass scan, where we first scan files containing container name and then all the rest files. * @param alreadyProcessedFiles the number of files scanned in previous pass. * @return true if completed */ private boolean processPsiFileRoots(@NotNull List<VirtualFile> files, final int totalSize, int alreadyProcessedFiles, @NotNull final ProgressIndicator progress, @NotNull final Processor<? super PsiFile> localProcessor) { myManager.startBatchFilesProcessingMode(); try { final AtomicInteger counter = new AtomicInteger(alreadyProcessedFiles); final AtomicBoolean canceled = new AtomicBoolean(false); boolean completed = true; while (true) { List<VirtualFile> failedList = new SmartList<VirtualFile>(); final List<VirtualFile> failedFiles = Collections.synchronizedList(failedList); final Processor<VirtualFile> processor = new Processor<VirtualFile>() { @Override public boolean process(final VirtualFile vfile) { try { TooManyUsagesStatus.getFrom(progress).pauseProcessingIfTooManyUsages(); processVirtualFile(vfile, progress, localProcessor, canceled, counter, totalSize); } catch (ApplicationUtil.CannotRunReadActionException action) { failedFiles.add(vfile); } return !canceled.get(); } }; if (ApplicationManager.getApplication().isWriteAccessAllowed() || ((ApplicationEx)ApplicationManager.getApplication()).isWriteActionPending()) { // no point in processing in separate threads - they are doomed to fail to obtain read action anyway completed &= ContainerUtil.process(files, processor); } else { completed &= JobLauncher.getInstance().invokeConcurrentlyUnderProgress(files, progress, false, false, processor); } if (failedFiles.isEmpty()) { break; } // we failed to run read action in job launcher thread // run read action in our thread instead to wait for a write action to complete and resume parallel processing DumbService.getInstance(myManager.getProject()).runReadActionInSmartMode(EmptyRunnable.getInstance()); files = failedList; } return completed; } finally { myManager.finishBatchFilesProcessingMode(); } }
private void processVirtualFile(@NotNull final VirtualFile vfile, @NotNull final ProgressIndicator progress, @NotNull final Processor<? super PsiFile> localProcessor, @NotNull final AtomicBoolean canceled, @NotNull AtomicInteger counter, int totalSize) throws ApplicationUtil.CannotRunReadActionException { final PsiFile file = ApplicationUtil.tryRunReadAction(new Computable<PsiFile>() { @Override public PsiFile compute() { return vfile.isValid() ? myManager.findFile(vfile) : null; } }); if (file != null && !(file instanceof PsiBinaryFile)) { // load contents outside read action if (FileDocumentManager.getInstance().getCachedDocument(vfile) == null) { // cache bytes in vfs try { vfile.contentsToByteArray(); } catch (IOException ignored) { } } ApplicationUtil.tryRunReadAction(new Computable<Void>() { @Override public Void compute() { final Project project = myManager.getProject(); if (project.isDisposed()) throw new ProcessCanceledException(); if (DumbService.isDumb(project)) throw new ApplicationUtil.CannotRunReadActionException(); List<PsiFile> psiRoots = file.getViewProvider().getAllFiles(); Set<PsiFile> processed = new THashSet<PsiFile>(psiRoots.size() * 2, (float)0.5); for (final PsiFile psiRoot : psiRoots) { progress.checkCanceled(); assert psiRoot != null : "One of the roots of file " + file + " is null. All roots: " + psiRoots + "; ViewProvider: " + file.getViewProvider() + "; Virtual file: " + file.getViewProvider().getVirtualFile(); if (!processed.add(psiRoot)) continue; if (!psiRoot.isValid()) { continue; } if (!localProcessor.process(psiRoot)) { canceled.set(true); break; } } return null; } }); } if (progress.isRunning()) { double fraction = (double)counter.incrementAndGet() / totalSize; progress.setFraction(fraction); } }
@NotNull public static CharSequence loadText(@NotNull final VirtualFile file) { if (file instanceof LightVirtualFile) { return ((LightVirtualFile)file).getContent(); } if (file.isDirectory()) { throw new AssertionError("'" + file.getPresentableUrl() + "' is a directory"); } FileType fileType = file.getFileType(); if (fileType.isBinary()) { final BinaryFileDecompiler decompiler = BinaryFileTypeDecompilers.INSTANCE.forFileType(fileType); if (decompiler != null) { CharSequence text; Application app = ApplicationManager.getApplication(); if (app != null && app.isDispatchThread() && !app.isWriteAccessAllowed() && !GraphicsEnvironment.isHeadless()) { final Ref<CharSequence> result = Ref.create(ArrayUtil.EMPTY_CHAR_SEQUENCE); final Ref<Throwable> error = Ref.create(); ProgressManager.getInstance().run(new Task.Modal(null, "Decompiling " + file.getName(), true) { @Override public void run(@NotNull ProgressIndicator indicator) { indicator.setIndeterminate(true); try { result.set(ApplicationUtil.runWithCheckCanceled(new Callable<CharSequence>() { @Override public CharSequence call() { return decompiler.decompile(file); } }, indicator)); } catch (Throwable t) { error.set(t); } } }); ExceptionUtil.rethrowUnchecked(error.get()); text = result.get(); } else { text = decompiler.decompile(file); } StringUtil.assertValidSeparators(text); return text; } throw new IllegalArgumentException("Attempt to load text for binary file which doesn't have a decompiler plugged in: " + file.getPresentableUrl() + ". File type: " + fileType.getName()); } try { byte[] bytes = file.contentsToByteArray(); return getTextByBinaryPresentation(bytes, file); } catch (IOException e) { return ArrayUtil.EMPTY_CHAR_SEQUENCE; } }
@Override public int getStartPosition() { return ApplicationUtil.tryRunReadAction(() -> selectionModel.getSelectionStart()); }
@Override public int getEndPosition() { return ApplicationUtil.tryRunReadAction(() -> selectionModel.getSelectionEnd()); }
@Override public Optional<String> getText() { String text = ApplicationUtil.tryRunReadAction(() -> selectionModel.getSelectedText()); return Optional.ofNullable(text); }
public static boolean processFilesConcurrentlyDespiteWriteActions(@Nonnull Project project, @Nonnull List<VirtualFile> files, @Nonnull final ProgressIndicator progress, @Nonnull final Processor<VirtualFile> localProcessor) { ApplicationEx app = (ApplicationEx)ApplicationManager.getApplication(); final AtomicBoolean canceled = new AtomicBoolean(false); while (true) { List<VirtualFile> failedList = new SmartList<>(); final List<VirtualFile> failedFiles = Collections.synchronizedList(failedList); final Processor<VirtualFile> processor = vfile -> { try { boolean result = localProcessor.process(vfile); if (!result) { canceled.set(true); } return result; } catch (ApplicationUtil.CannotRunReadActionException action) { failedFiles.add(vfile); } return !canceled.get(); }; boolean completed; if (app.isWriteAccessAllowed() || app.isReadAccessAllowed() && app.isWriteActionPending()) { // no point in processing in separate threads - they are doomed to fail to obtain read action anyway completed = ContainerUtil.process(files, processor); } else if (app.isWriteActionPending()) { completed = true; // we don't have read action now so wait for write action to complete failedFiles.addAll(files); } else { // try to run parallel read actions but fail as soon as possible completed = JobLauncher.getInstance().invokeConcurrentlyUnderProgress(files, progress, false, true, processor); } if (!completed) { return false; } if (failedFiles.isEmpty()) { break; } // we failed to run read action in job launcher thread // run read action in our thread instead to wait for a write action to complete and resume parallel processing DumbService.getInstance(project).runReadActionInSmartMode(EmptyRunnable.getInstance()); files = failedList; } return true; }
private void throwIfImpatient(Reader status) { // when client explicitly runs in non-cancelable block do not throw from within nested read actions if (status.impatientReads && writeRequested && !ProgressManager.getInstance().isInNonCancelableSection() && CoreProgressManager.ENABLED) { throw ApplicationUtil.CannotRunReadActionException.create(); } }