Runnable (@NotNull final ProgressIndicator indicator) { try { indicator.checkCanceled(); List<DiffContent> contents = myRequest.getContents(); if (!(contents.get(0) instanceof FileContent) || !(contents.get(1) instanceof FileContent)) { return applyNotification(ComparisonData.UNKNOWN); } final VirtualFile file1 = ((FileContent)contents.get(0)).getFile(); final VirtualFile file2 = ((FileContent)contents.get(1)).getFile(); ComparisonData comparisonData = ReadAction.nonBlocking(() -> { if (!file1.isValid() || !file2.isValid()) { return ComparisonData.ERROR; } long length1 = file1.getLength(); long length2 = file2.getLength(); try { boolean contentsEquals; if (length1 > 0 && length2 > 0 && length1 != length2) { // Can't trust 0 length, at it might be a lie (and loading empty content into memory shouldn't hurt much). contentsEquals = false; } else if (FileUtilRt.isTooLarge(length1) || FileUtilRt.isTooLarge(length2)) { return new ComparisonData(ThreeState.UNSURE, () -> DiffBundle.message("error.files.too.large.to.compare.text")); } else { contentsEquals = DiffUtil.compareStreams(() -> DiffUtil.getFileInputStream(file1), () -> DiffUtil.getFileInputStream(file2)); } return new ComparisonData(ThreeState.fromBoolean(contentsEquals), () -> contentsEquals ? DiffBundle.message("diff.contents.are.identical.message.text") : null); } catch (IOException e) { LOG.warn(e); return ComparisonData.ERROR; } }) .wrapProgress(indicator) .executeSynchronously(); return applyNotification(comparisonData); } catch (ProcessCanceledException e) { throw e; } catch (Throwable e) { LOG.error(e); return applyNotification(ComparisonData.ERROR); } }